Plugins/Community Based Plugins/Microsoft Defender XDR Custom Plugin Scenarios/EnrichmentPlugins/PurviewEnrichment.yaml (2,119 lines of code) (raw):

Descriptor: Name: DataSecurityAnalyst DisplayName: Purview - Triage, investigation, analysis, tuning Description: Data Security skills to query DLP events and file activities for Users and devices and correlate with other event types SkillGroups: - Format: KQL Skills: - Name: DLPGetlatestDlpalertperuser DisplayName: Get Latest DLP alerts by user Description: Fetches the latest dlp events, alerts generated by the user Inputs: - Name: User Description: The user associated with the alert Required: true Settings: Target: Defender Template: |- let user = '{{User}}'; CloudAppEvents | where ActionType has "DLPRuleMatch" or ActionType has "DLPRuleUndo" or RawEventData.PolicyMatchInfo.PolicyId <> "" | where ActionType !in ('FileRead','FileArchived','FileModified','FileRenamed') | where parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].Actions))[0] !in ('Encrypt','ExApplyBrandingTemplate') | where tolower(RawEventData.UserId) has tolower(user) | extend PolicyName_ = tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].PolicyName) | extend SensitiveInformationTypeName_ = tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].ConditionsMatched)).SensitiveInformation))[0].SensitiveInformationTypeName) | extend FileName_ = tostring(parse_json(tostring(RawEventData.SharePointMetaData)).FileName) | extend RuleName_ = tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].RuleName) | extend Severity_ = tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].Severity) | extend Attachments_ = tostring(parse_json(tostring(RawEventData.Item)).Attachments) | extend Recipients = strcat("To:",RawEventData.ExchangeMetaData.To, " CC:",RawEventData.ExchangeMetaData.CC," BCC:",RawEventData.ExchangeMetaData.BCC) | extend SharePointMetaData_SiteCollectionUrl_s = tostring(parse_json(tostring(RawEventData.SharePointMetaData)).SiteCollectionUrl) | extend Documents = iff(isempty(FileName_), Attachments_, FileName_) | join kind = leftouter ( CloudAppEvents | where RawEventData.Operation == "SecureLinkUsed" or RawEventData.Operation == "AddedToSecureLink" | extend SourceFileName = tostring(RawEventData.SourceFileName) | extend SharePointMetaData_SiteCollectionUrl_s = tostring(RawEventData.SiteUrl) | extend UserId = tostring(RawEventData.UserId) | extend TargetUserOrGroupName = tostring(RawEventData.TargetUserOrGroupName) | summarize by SharePointMetaData_SiteCollectionUrl_s,SourceFileName,TargetUserOrGroupName | summarize TargetUserOrGroupName = make_list(strcat(TargetUserOrGroupName)) by SharePointMetaData_SiteCollectionUrl_s,SourceFileName | summarize take_any(TargetUserOrGroupName) by SourceFileName,SharePointMetaData_SiteCollectionUrl_s |project SourceFileName, SharePointMetaData_SiteCollectionUrl_s, TargetUserOrGroupName ) on SharePointMetaData_SiteCollectionUrl_s | extend TargetUsers = iff(isnotempty(tostring(TargetUserOrGroupName)), tostring(TargetUserOrGroupName), Recipients) | extend Subject = tostring(parse_json(tostring(RawEventData.ExchangeMetaData)).Subject) | extend PolicyName_EndPoint = tostring(parse_json(tostring(RawEventData.PolicyMatchInfo)).PolicyName) | extend PolicyName = iff(isempty(PolicyName_), PolicyName_EndPoint, PolicyName_) | extend Workload = tostring(RawEventData.Workload) | extend Object = tostring(RawEventData.ObjectId) | join kind=leftouter ( CloudAppEvents | where RawEventData.Workload has "Endpoint" | extend SensitiveInfoTypeName_ = tostring(parse_json(tostring(RawEventData.SensitiveInfoTypeData))[0].SensitiveInfoTypeName) | where SensitiveInfoTypeName_ <> "" | extend EndPointFile = tostring(RawEventData.ObjectId) | extend PolicyName = tostring(parse_json(tostring(RawEventData.PolicyMatchInfo)).PolicyName) | project EndPointFile,SensitiveInfoTypeName_,PolicyName ) on $left.Object == $right.EndPointFile | extend Documents = iff(isempty(Documents), EndPointFile, Documents) | extend SensitiveInformationType = iff(isempty(SensitiveInformationTypeName_), SensitiveInfoTypeName_, SensitiveInformationTypeName_) | extend EndpointOperation_ = tostring(parse_json(tostring(RawEventData.EndpointMetaData)).EndpointOperation) | extend TargetDomain = tostring(parse_json(tostring(RawEventData.EndpointMetaData)).TargetDomain) | extend Target = iff(isempty(tostring(TargetDomain)), TargetUsers, tostring(TargetDomain)) | project Timestamp,ActionType,Workload,PolicyName,SensitiveInformationType,Documents,Target,Subject,Severity_ | summarize arg_max(Timestamp, *) by Workload,PolicyName,SensitiveInformationType,Documents,Target | sort by Timestamp - Name: DLPgetAllDlpalerts DisplayName: Get all dlp alerts so that they can be analyzed Description: Fetches all dlp alerts so that they can be analyzed Inputs: - Name: workload Description: Specify the workload for which the alerts are to be fetched Required: false Settings: Target: Defender Template: |- let workload = '{{workload}}'; let EndPointAction = datatable(ActionName: string, Action: int) [ 'None', '0', 'Audit', '1', 'Warn', '2', 'WarnAndBypass', '3', 'Block', '4', 'Allow', '5' ]; CloudAppEvents //| search incident | where ActionType has 'DLPRuleMatch' or ActionType has "DLPRuleUndo" or RawEventData.PolicyMatchInfo.PolicyId <> "" | where ActionType !in ('FileRead','FileArchived','FileModified','FileRenamed') | where RawEventData.Workload has workload | extend CreationTime = tostring(RawEventData.CreationTime) | extend User = tolower(RawEventData.UserId) //| project RawEventData,RawEventData2,User,RawEventData2.ObjectId,RawEventData.Workload,Timestamp | where parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].Actions))[0] !in ('Encrypt','ExApplyBrandingTemplate') | extend PolicyName_ = tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].PolicyName) | extend Action = tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].Actions))) | extend RuleName_ = tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].RuleName) | extend classifiermatch = tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].ConditionsMatched)).SensitiveInformation))) | extend PolicyName_ = tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].PolicyName) | extend SensitiveInformationTypeName_ = tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].ConditionsMatched)).SensitiveInformation))[0].SensitiveInformationTypeName) | extend FileName_ = tostring(parse_json(tostring(RawEventData.SharePointMetaData)).FileName) | extend RuleName_ = tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].RuleName) | extend Severity_ = tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].Severity) | extend Attachments_ = tostring(parse_json(tostring(RawEventData.Item)).Attachments) | extend Recipients = strcat('To:',RawEventData.ExchangeMetaData.To, ' CC:',RawEventData.ExchangeMetaData.CC,' BCC:',RawEventData.ExchangeMetaData.BCC) | extend SharePointMetaData_SiteCollectionUrl_s = tostring(parse_json(tostring(RawEventData.SharePointMetaData)).SiteCollectionUrl) | extend Documents = iff(isempty(FileName_), Attachments_, FileName_) | extend endpointdata = (parse_json(RawEventData.EndpointMetaData)) | extend EndPointAction = toint(RawEventData.EnforcementMode) | extend EndPointFile = tostring(RawEventData.ObjectId) | join kind= leftouter ( EndPointAction ) on $left.EndPointAction==$right.Action | extend Action = iff(isempty(Action), tolower(ActionName), Action) | extend endpointclassifiermatch = endpointdata.SensitiveInfoTypeData | extend Documents = iff(isempty(Documents), EndPointFile, Documents) | mv-expand RawEventData.SensitiveInfoTypeData | extend SensitiveInfoTypeName_ = tostring(RawEventData_SensitiveInfoTypeData.SensitiveInfoTypeName) | extend SensitiveInformationType = iff(isempty(SensitiveInformationTypeName_), SensitiveInfoTypeName_, SensitiveInformationTypeName_) | extend EndpointOperation_ = ActionType | extend TargetDomain = tostring(parse_json(tostring(RawEventData.EndpointMetaData)).TargetDomain) | extend Subject = tostring(parse_json(tostring(RawEventData.ExchangeMetaData)).Subject) | project Workload = tostring(RawEventData.Workload),Action,User,SensitiveInformationType,EndpointOperation_,TargetDomain,Subject,Documents,Recipients,Timestamp | summarize arg_max(Timestamp, *) by User,SensitiveInformationType,Subject,EndpointOperation_ | sort by Timestamp - Name: DLPgetalertbyPolicy DisplayName: Get the DLP alerts by policy Description: Fetches all dlp alerts associated with a specific policy Inputs: - Name: policy Description: Specify the policy for which the alerts are to be fetched Required: false Settings: Target: Defender Template: |- let policyvar = '{{policy}}'; let workload = ''; let EndPointAction = datatable(ActionName: string, Action: int) [ 'None', '0', 'Audit', '1', 'Warn', '2', 'WarnAndBypass', '3', 'Block', '4', 'Allow', '5' ]; CloudAppEvents //| search incident | where ActionType has 'DLPRuleMatch' or ActionType has "DLPRuleUndo" or RawEventData.PolicyMatchInfo.PolicyId <> "" | where ActionType !in ('FileRead','FileArchived','FileModified','FileRenamed') | where RawEventData.Workload has workload | extend CreationTime = tostring(RawEventData.CreationTime) | extend User = tolower(RawEventData.UserId) | where parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].Actions))[0] !in ('Encrypt','ExApplyBrandingTemplate') | extend Action = tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].Actions))) | extend PolicyName_ = tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].PolicyName) | extend PolicyNameEP = tostring(parse_json(tostring(RawEventData.MatchedPolicies))[0].PolicyName) | extend PolicyName = iff(isempty(PolicyName_),PolicyNameEP,PolicyName_) | where PolicyName has policyvar | extend RuleName_ = tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].RuleName) | extend classifiermatch = tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].ConditionsMatched)).SensitiveInformation))) | extend SensitiveInformationTypeName_ = tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].ConditionsMatched)).SensitiveInformation))[0].SensitiveInformationTypeName) | extend FileName_ = tostring(parse_json(tostring(RawEventData.SharePointMetaData)).FileName) | extend RuleName_ = tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].RuleName) | extend Severity_ = tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].Severity) | extend Attachments_ = tostring(parse_json(tostring(RawEventData.Item)).Attachments) | extend Recipients = strcat('To:',RawEventData.ExchangeMetaData.To, ' CC:',RawEventData.ExchangeMetaData.CC,' BCC:',RawEventData.ExchangeMetaData.BCC) | extend SharePointMetaData_SiteCollectionUrl_s = tostring(parse_json(tostring(RawEventData.SharePointMetaData)).SiteCollectionUrl) | extend Documents = iff(isempty(FileName_), Attachments_, FileName_) | extend endpointdata = (parse_json(RawEventData.EndpointMetaData)) | extend EndPointAction = toint(RawEventData.EnforcementMode) | extend EndPointFile = tostring(RawEventData.ObjectId) | join kind= leftouter ( EndPointAction ) on $left.EndPointAction==$right.Action | extend Action = iff(isempty(Action), tolower(ActionName), Action) | extend endpointclassifiermatch = endpointdata.SensitiveInfoTypeData | extend Documents = iff(isempty(Documents), EndPointFile, Documents) | mv-expand RawEventData.SensitiveInfoTypeData | extend SensitiveInfoTypeName_ = tostring(RawEventData_SensitiveInfoTypeData.SensitiveInfoTypeName) | extend SensitiveInformationType = iff(isempty(SensitiveInformationTypeName_), SensitiveInfoTypeName_, SensitiveInformationTypeName_) | extend EndpointOperation_ = ActionType | extend TargetDomain = tostring(parse_json(tostring(RawEventData.EndpointMetaData)).TargetDomain) | extend Subject = tostring(parse_json(tostring(RawEventData.ExchangeMetaData)).Subject) | project Workload = tostring(RawEventData.Workload),Action,User,SensitiveInformationType,EndpointOperation_,TargetDomain,Subject,Documents,Recipients,PolicyName,Timestamp | summarize arg_max(Timestamp, *) by User,SensitiveInformationType,Subject,PolicyName | sort by Timestamp - Name: DLPgetFileactivity DisplayName: Get the file activity of the specified file Description: Fetches the file activity of the latest file including labels and sensitive information Inputs: - Name: document Description: The file activity associated with the specific file Required: true Settings: Target: Defender Template: |- let document = '{{document}}'; CloudAppEvents | extend sit = parse_json(tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].ConditionsMatched)).SensitiveInformation)) | mv-expand sit | where sit.Location has document or tostring(parse_json(tostring(RawEventData.Item)).Attachments) has document or url_decode(ObjectName) has document or RawEventData.ObjectId has document or RawEventData.ItemName has document or RawEventData.DestinationFileName has document | extend User = tostring(RawEventData.UserId) | extend LabelGUID1 = parse_json(tostring(RawEventData.SensitivityLabelEventData)).SensitivityLabelId | extend LabelGUID2 = iff(isempty(tostring(RawEventData.LabelId)), LabelGUID1, tostring(RawEventData.LabelId)) | extend LabelGUID3 = iff(isempty(tostring(RawEventData.SensitivityLabelId)), LabelGUID2, tostring(RawEventData.SensitivityLabelId)) | extend OldSensitivityLabelId = tostring(parse_json(tostring(RawEventData.SensitivityLabelEventData)).OldSensitivityLabelId) | extend LabelGUID = iff(isempty(tostring(LabelGUID3)),OldSensitivityLabelId, tostring(LabelGUID3)) | mv-expand PolicyDetails = RawEventData.PolicyDetails | mv-expand Rules = PolicyDetails.Rules | mv-expand Sensitive = Rules.ConditionsMatched.SensitiveInformation | extend sit = parse_json(tostring(RawEventData.SensitiveInfoTypeData)) | mv-expand sit | extend sit = iff(isempty(sit.SensitiveInfoTypeName),Sensitive.SensitiveInformationTypeName,sit.SensitiveInfoTypeName) | extend SensitiveInfoTypeName = tostring(sit) | project Timestamp,Activity=ActionType,User,CountryCode,LabelGUID,SensitiveInfoTypeName | sort by Timestamp - Name: DLPgetEndpointactivity DisplayName: Get the sensitive file activity of the specified Device Description: Fetches the sensitive file activity happening on the Device Inputs: - Name: device Description: The file activity associated with the specific device Required: true Settings: Target: Defender Template: |- let devicevar = '{{device}}'; let AppEvents = (CloudAppEvents | where parse_json(tostring(RawEventData.SensitiveInfoTypeData)) != "" | where parse_json(tostring(RawEventData.SensitiveInfoTypeData)) != "[]" | extend sit = parse_json(tostring(RawEventData.SensitiveInfoTypeData)) | mv-expand sit | extend UserId = tolower(RawEventData.UserId) | extend SensitiveInfoTypeName = tostring(sit.SensitiveInfoTypeName) | extend document = tostring(RawEventData.ObjectId) ); AppEvents | where tolower(RawEventData.DeviceName) == tolower(devicevar) | extend ObjectId = tostring(RawEventData.ObjectId) | extend DeviceName = tostring(RawEventData.DeviceName) | extend Application = tostring(RawEventData.Application) | summarize count = count() by document,Application,SensitiveInfoTypeName,ActionType,DeviceName,CountryCode |order by ActionType - Name: DLPgetSiteCollectionActivity DisplayName: Get the SharePoint site collection or library activity of the specified collection Description: Fetches the SharePoint site collection or library activity of the selected collection Inputs: - Name: sitecollection Description: The site or library activity associated with the specified collection Required: true Settings: Target: Defender Template: |- let sitecollection = '{{sitecollection}}'; CloudAppEvents | where RawEventData.Workload == "OneDrive" or RawEventData.Workload == "SharePoint" | where RawEventData.ObjectId has sitecollection | extend Operation = tostring(RawEventData.Operation) //Filter to a smaller set of operations, add additional operations as needed | where Operation in ('FileAccessed','FilePreviewed','FileModifiedExtended','FileSensitivityLabelApplied','FileModified','FileUploaded','FileDownloaded','FileRenamed','AddedToSecureLink','SharingSet','SecureLinkCreated','SharingInheritanceBroken','FileSensitivityLabelChanged','CompanyLinkUsed','CompanyLinkCreated','SharingRevoked','FileSyncDownloadedFull','AddedToGroup','FileSensitivityLabelRemoved') | extend Account = tostring(RawEventData.UserId) | extend SharePointMetaData_SiteCollectionUrl_s = tostring((RawEventData.SharePointMetaData.SiteCollectionUrl)) | extend FilePathUrl_ = url_decode(tostring(parse_json(tostring(RawEventData.SharePointMetaData)).FilePathUrl)) | extend SourceRelativeUrl = tostring(RawEventData.SourceRelativeUrl) | extend SourceFileName_ = tostring(RawEventData.SourceFileName) | extend TargetUserOrGroupName = tostring(RawEventData.TargetUserOrGroupName) | summarize by Timestamp, Operation, SourceFileName_, Account, SourceRelativeUrl, TargetUserOrGroupName | sort by Timestamp - Name: DLPTeamsDetectionsUser DisplayName: Get all the meetings, chats and channel messages that triggered an alert for a user or recipient Description: Fetches all the meetings, chats and channel messages that triggered an alert for a user or recipient Inputs: - Name: Recipient Description: The recipient associated with the alert Required: false - Name: User Description: the user associated with the information Required: false Settings: Target: Defender Template: |- let Recipient = '{{Recipient}}'; let user = '{{User}}'; let TeamsMeeting = ( CloudAppEvents | where Application == 'Microsoft Teams' | where ActionType == 'DLPRuleMatch' | extend UserId_ = tostring(RawEventData.UserId) | extend Workload_ = tostring(RawEventData.Workload) | extend ObjectId_ = tostring(RawEventData.ObjectId) | extend MessageId_ = ObjectId_ | join kind=leftouter ( CloudAppEvents | where RawEventData.Name == 'policyViolation' | extend MessageId_ = tostring(RawEventData.MessageId) | extend MeetingDetailId_ = tostring(RawEventData.MeetingDetailId) ) on MessageId_ | extend ChatThreadId_ = tostring(RawEventData1.ItemName) | join kind=inner ( CloudAppEvents | where RawEventData.Operation == 'MeetingDetail' | extend ChatThreadId_ = tostring(RawEventData.ChatThreadId) | extend meetid = tostring(RawEventData.Id) ) on ChatThreadId_ | extend Meeting = tostring(parse_json(tostring(parse_json(tostring(RawEventData.ExchangeMetaData)).To))[0]) | extend PolicyName = tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].PolicyName) | extend RuleName = tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].RuleName) | extend SensitiveInformationTypeName = tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].ConditionsMatched)).SensitiveInformation))[0].SensitiveInformationTypeName) | project meetid,Meeting,PolicyName,RuleName,SensitiveInformationTypeName,UserId_ | join kind=inner ( CloudAppEvents | where RawEventData.Operation == 'MeetingParticipantDetail' | extend meetid = tostring(RawEventData.MeetingDetailId) ) on meetid | extend UPN = tostring(parse_json(tostring(RawEventData.Attendees))[0].UPN) | extend RecipientType = tostring(parse_json(tostring(RawEventData.Attendees))[0].RecipientType) //| where RecipientType startswith 'Guest' | extend Type = "TeamsMeeting" | project Type,UPN,RecipientType,Meeting,PolicyName,RuleName,SensitiveInformationTypeName,UserId_); let channel =( CloudAppEvents | where Application == 'Microsoft Teams' | where ActionType == 'DLPRuleMatch' | extend UserId_ = tostring(RawEventData.UserId) | extend TeamName = tolower(parse_json(tostring(parse_json(tostring(RawEventData.ExchangeMetaData)).To))[0]) | extend PolicyName = tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].PolicyName) | extend RuleName = tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].RuleName) | extend SensitiveInformationTypeName = tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].ConditionsMatched)).SensitiveInformation))[0].SensitiveInformationTypeName) | join kind=inner ( CloudAppEvents | where Application == 'Microsoft Teams' | extend TeamName = tolower(RawEventData.TeamName) | extend UPN = tostring(parse_json(tostring(RawEventData.Members))[0].UPN) | extend GroupId = tostring(RawEventData.AADGroupId) | extend HasGuestUsers = tostring(parse_json(tostring(RawEventData.ParticipantInfo)).HasGuestUsers) | extend HasUnauthenticatedUsers = tostring(parse_json(tostring(RawEventData.ParticipantInfo)).HasUnauthenticatedUsers) ) on TeamName | where HasGuestUsers == 'true' or HasUnauthenticatedUsers == 'true' | project TeamName,ActionType,HasGuestUsers,HasUnauthenticatedUsers,UPN,PolicyName,RuleName,SensitiveInformationTypeName,UserId_ | extend Type = "TeamChannel"); let individual = ( CloudAppEvents | where Application == 'Microsoft Teams' | where ActionType has 'DLPRuleMatch' | extend UPN = tostring(parse_json(tostring(parse_json(tostring(RawEventData.ExchangeMetaData)).To))[0]) | where UPN matches regex '(\\S*@\\S*.\\S*)' | extend UserId_ = tostring(RawEventData.UserId) | extend TeamName = tolower(parse_json(tostring(parse_json(tostring(RawEventData.ExchangeMetaData)).To))[0]) | extend PolicyName = tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].PolicyName) | extend RuleName = tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].RuleName) | extend SensitiveInformationTypeName = tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].ConditionsMatched)).SensitiveInformation))[0].SensitiveInformationTypeName) | extend Type = "Individual"); union channel,TeamsMeeting,individual | where UserId_ has user | where UPN has Recipient | extend Name = iff(isempty(TeamName),Meeting,TeamName) | summarize by Type,User=UserId_,Name,Target=UPN,PolicyName,SensitiveInformationTypeName - Name: DLPFilesSharedwithUser DisplayName: Get the file and shared user information Description: Fetches all information associated with Shared information and user Inputs: - Name: document Description: the file associated with the user activity Required: true - Name: User Description: the user associated with the information Required: false Settings: Target: Defender Template: |- let document = '{{document}}'; let user = '{{User}}'; let DLP = (CloudAppEvents | where RawEventData.Workload in ('SharePoint', 'OneDrive') | where ActionType == "DLPRuleMatch" | extend FilePathUrl_ = url_decode(tostring(RawEventData.SharePointMetaData.FilePathUrl)) | extend path = parse_path(FilePathUrl_) | where path.Filename has document | extend DirectoryPath = tostring(path.DirectoryPath) | summarize by DirectoryPath ); let officedata = ( CloudAppEvents | where RawEventData.Operation == "SecureLinkUsed" or RawEventData.Operation == "AddedToSecureLink" | extend ObjectId_ = tostring(RawEventData.ObjectId) | where ObjectId_ has_any (DLP) | extend SharePointMetaData_SiteCollectionUrl = tostring(RawEventData.SiteUrl) | extend SharePointMetaData_FileName = tostring((RawEventData.SourceFileName)) | extend Account = tostring(RawEventData.UserId) | extend Targetsplit = split(Account, "#") | extend TargetUserOrGroupName = iff(isempty(RawEventData.TargetUserOrGroupName), Targetsplit[1], RawEventData.TargetUserOrGroupName) //Exclude internal domains if required //| where TargetUserOrGroupName !has "mydom1.com" | extend TargetUserOrGroupName = tolower(TargetUserOrGroupName) | summarize by SharePointMetaData_FileName, SharePointMetaData_SiteCollectionUrl, TargetUserOrGroupName, ObjectId_, Account); let dlpmain = ( CloudAppEvents | where ActionType == "DLPRuleMatch" | where RawEventData.Workload == "OneDrive" or RawEventData.Workload == "SharePoint" | extend FilePathUrl_ = url_decode(tostring(RawEventData.SharePointMetaData.FilePathUrl)) | extend path = parse_path(FilePathUrl_) | where path.Filename has document | extend Account = tostring(RawEventData.UserId) | where Account has user | extend ObjectId_ = url_decode(tostring(ObjectName)) | extend SharePointMetaData_SiteCollectionUrl = tostring((RawEventData.SharePointMetaData.SiteCollectionUrl)) | where tolower(RawEventData.UserId) == tolower(Account) | where RawEventData.Workload in ('SharePoint', 'OneDrive') | extend SourceFileName = tostring(RawEventData.SourceFileName) ); let folder = (dlpmain | join kind = leftouter (officedata | summarize by SharePointMetaData_SiteCollectionUrl, SharePointMetaData_FileName, TargetUserOrGroupName, ObjectId_ | summarize TargetUserOrGroupName = make_list(strcat(TargetUserOrGroupName)) by ObjectId_, SharePointMetaData_SiteCollectionUrl, SharePointMetaData_FileName | summarize take_any(TargetUserOrGroupName) by ObjectId_, SharePointMetaData_SiteCollectionUrl, SharePointMetaData_FileName | join kind = leftouter ( officedata | summarize by SharePointMetaData_SiteCollectionUrl, SharePointMetaData_FileName, TargetUserOrGroupName, ObjectId_ | extend Domsplit = split(TargetUserOrGroupName, "@") | extend domain = Domsplit[1] | summarize TargetDomain = make_list(strcat(domain)) by SharePointMetaData_FileName, ObjectId_ | summarize take_any(TargetDomain) by SharePointMetaData_FileName, ObjectId_ ) on ObjectId_ ) on ObjectId_ ); let files = (folder //| where TargetUserOrGroupName == "" | join kind = leftouter (officedata | summarize TargetUserOrGroupName = make_list(strcat(TargetUserOrGroupName)) by SharePointMetaData_FileName, SharePointMetaData_SiteCollectionUrl | summarize take_any(TargetUserOrGroupName) by SharePointMetaData_FileName, SharePointMetaData_SiteCollectionUrl | join kind = leftouter ( officedata | summarize by SharePointMetaData_SiteCollectionUrl, SharePointMetaData_FileName, TargetUserOrGroupName | extend Domsplit = split(TargetUserOrGroupName, "@") | extend domain = Domsplit[1] | summarize TargetDomain = make_list(strcat(domain)) by SharePointMetaData_FileName | summarize take_any(TargetDomain) by SharePointMetaData_FileName ) on SharePointMetaData_FileName ) on SharePointMetaData_FileName, SharePointMetaData_SiteCollectionUrl | extend TargetUserOrGroupName = TargetUserOrGroupName1 | extend TargetDomain = TargetDomain1 | where TargetUserOrGroupName != "" ); union folder, files | extend FileName = tostring(parse_json(tostring(RawEventData.SharePointMetaData)).FileName) | summarize arg_max(Timestamp, *) by ObjectId_, Account, tostring(RawEventData.Id) | extend FileNameEncoded = url_encode(FileName) | extend MDALink = (strcat('https://security.microsoft.com/cloudapps/files?filename=eq(',FileNameEncoded,')')) //Use this link to view older operations directly from Microsoft Defender for Cloud Apps | project Timestamp,FileName,TargetUser= TargetUserOrGroupName,SiteCollection = ObjectId_ | sort by Timestamp - Name: DLPAnomalies DisplayName: Get DLP anomalies or outliers from the log stream Description: Fetches anomalies or outliers from the log stream Settings: Target: Defender Template: |- CloudAppEvents | where ActionType == "DlpRuleMatch" | extend UserId = tostring(RawEventData.UserId) | summarize EventCount=count() by UserId, bin(Timestamp,30m) | order by Timestamp | summarize EventCount=make_list(EventCount),TimeGenerated=make_list(Timestamp) by UserId | extend outliers=series_decompose_anomalies(EventCount) | mv-expand TimeGenerated, EventCount, outliers | where outliers == 1 | summarize aggregate=sum(todecimal(EventCount)) by UserId - Name: DLPExchangeTuning DisplayName: Receive DLP tuning recommendations for Exchange Description: This skill provides tuning and optimization recommendations for DLP policies in Exchange Settings: Target: Defender Template: |- let Exchange = ( CloudAppEvents | where ActionType has 'DLPRuleMatch' | where RawEventData.Workload has 'Exchange' | extend To = todynamic(parse_json(tostring(parse_json(RawEventData.ExchangeMetaData).To))) | extend PolicyName = tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].PolicyName) | extend SensitiveInformationTypeName = tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].ConditionsMatched)).SensitiveInformation))[0].SensitiveInformationTypeName)); let To = ( Exchange | extend Type = 'To' | extend To = todynamic(parse_json(tostring(parse_json(RawEventData.ExchangeMetaData).To))) | mv-expand To | summarize count() by tostring(To),PolicyName,tostring(RawEventData.Workload),Type,SensitiveInformationTypeName | take 25); let From = ( Exchange | extend Type = 'From' | extend From = tostring(parse_json(tostring(RawEventData.ExchangeMetaData)).From) | summarize count() by From,PolicyName,tostring(RawEventData.Workload),Type,SensitiveInformationTypeName | take 25 ); let Location = ( Exchange | extend Type = 'MatchLocation' | extend Location = tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].ConditionsMatched)).SensitiveInformation))[0].Location) | extend PolicyName = tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].PolicyName) | summarize count() by Location,PolicyName,SensitiveInformationTypeName,tostring(RawEventData.Workload),Type |take 25 ); let Sensitive = ( Exchange | extend Type = 'SensitiveInformationType' | extend PolicyName = tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].PolicyName) | summarize count() by SensitiveInformationTypeName,PolicyName,tostring(RawEventData.Workload),Type |take 25 ); let domains = ( Exchange | extend Type = 'Targetdomains' | extend To = todynamic(parse_json(tostring(parse_json(RawEventData.ExchangeMetaData).To))) | mv-expand To | extend user = split(To,'@') | summarize count() by Targetdomain=tostring(user[1]),PolicyName,tostring(RawEventData.Workload),Type,SensitiveInformationTypeName | take 25 ); let subject = ( Exchange | extend Type = 'subject' | extend Subject = tostring(parse_json(tostring(RawEventData.ExchangeMetaData)).Subject) | summarize count() by Subject,PolicyName,tostring(RawEventData.Workload),Type,SensitiveInformationTypeName | take 25); union To, From, Location, Sensitive,domains,subject - Name: DLPSharePointTuning DisplayName: Receive DLP tuning recommendations for SharePoint and OneDrive Description: This skill provides tuning recommendations for DLP policies in SharePoint and OneDrive Settings: Target: Defender Template: |- let SPO = ( CloudAppEvents | where ActionType == 'DLPRuleMatch' | where RawEventData.Workload == 'OneDrive' or RawEventData.Workload == 'SharePoint' | extend Account = tostring(RawEventData.UserId) | extend SharePointMetaData_SiteCollectionUrl_s = tostring((RawEventData.SharePointMetaData.SiteCollectionUrl)) | extend PolicyName = tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].PolicyName) | extend FileName = tostring(parse_json(tostring(RawEventData.SharePointMetaData)).FileName) | extend SensitiveInformationTypeName = tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].ConditionsMatched)).SensitiveInformation))[0].SensitiveInformationTypeName) | join kind = inner ( CloudAppEvents | where RawEventData.Operation == 'SecureLinkUsed' or RawEventData.Operation == 'AddedToSecureLink' | extend SourceFileName = tostring(RawEventData.SourceFileName) | extend SharePointMetaData_SiteCollectionUrl_s = tostring(RawEventData.SiteUrl) | extend UserId = tostring(RawEventData.UserId) | extend TargetUserOrGroupName = tostring(RawEventData.TargetUserOrGroupName) | extend Sharedwith= iff(isempty(TargetUserOrGroupName), UserId, TargetUserOrGroupName) |project SourceFileName, SharePointMetaData_SiteCollectionUrl_s, TargetUserOrGroupName, Sharedwith ) on SharePointMetaData_SiteCollectionUrl_s | project Timestamp,Account,SharePointMetaData_SiteCollectionUrl_s, SourceFileName, Sharedwith,RawEventData,PolicyName,FileName,SensitiveInformationTypeName | sort by Timestamp); let Account = ( SPO | summarize count() by Account | extend Type = 'Account' | take 25); let Target = ( SPO | extend Type = 'Target' | summarize count() by Targetuser=Sharedwith,Type | take 25); let TargetDom = ( SPO | extend Type = 'domains' | extend TargetDom = split(Sharedwith,'@') | summarize count() by targetDomain=tostring(TargetDom[1]),Type | take 25); let TopSites = ( SPO | extend Type = 'TopSites' | summarize count() by SharePointMetaData_SiteCollectionUrl_s,Type,SensitiveInformationTypeName | take 25); let TopDocs = ( SPO | extend Type = 'TopDocs' | summarize count() by FileName,Type,SensitiveInformationTypeName | take 25); let TopSIT = ( SPO | extend Type = 'TopSIT' | summarize count() by Type,SensitiveInformationTypeName | take 25); union TargetDom,Account,Target,TopSites,TopDocs,TopSIT - Name: DLPTeamsTuning DisplayName: Receive DLP tuning recommendations for Teams Description: This skill provides tuning recommendations for DLP policies in Teams Settings: Target: Defender Template: |- let TeamsMeeting = ( CloudAppEvents | where Application == 'Microsoft Teams' | where ActionType == 'DLPRuleMatch' | extend UserId_ = tostring(RawEventData.UserId) | extend Workload_ = tostring(RawEventData.Workload) | extend ObjectId_ = tostring(RawEventData.ObjectId) | extend MessageId_ = ObjectId_ | join kind=inner ( CloudAppEvents | where RawEventData.Name == 'policyViolation' | extend MessageId_ = tostring(RawEventData.MessageId) | extend MeetingDetailId_ = tostring(RawEventData.MeetingDetailId) ) on MessageId_ | extend ChatThreadId_ = tostring(RawEventData1.ItemName) | join kind=inner ( CloudAppEvents | where RawEventData.Operation == 'MeetingDetail' | extend ChatThreadId_ = tostring(RawEventData.ChatThreadId) | extend meetid = tostring(RawEventData.Id) ) on ChatThreadId_ | extend Meeting = tostring(parse_json(tostring(parse_json(tostring(RawEventData.ExchangeMetaData)).To))[0]) | extend PolicyName = tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].PolicyName) | extend RuleName = tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].RuleName) | extend SensitiveInformationTypeName = tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].ConditionsMatched)).SensitiveInformation))[0].SensitiveInformationTypeName) | project meetid,Meeting,PolicyName,RuleName,SensitiveInformationTypeName,UserId_ | join kind=inner ( CloudAppEvents | where RawEventData.Operation == 'MeetingParticipantDetail' | extend meetid = tostring(RawEventData.MeetingDetailId) ) on meetid | extend UPN = tostring(parse_json(tostring(RawEventData.Attendees))[0].UPN) | extend RecipientType = tostring(parse_json(tostring(RawEventData.Attendees))[0].RecipientType) | where RecipientType startswith 'Guest' | project UPN,RecipientType,Meeting,PolicyName,RuleName,SensitiveInformationTypeName,UserId_); let channel =( CloudAppEvents | where Application == 'Microsoft Teams' | where ActionType == 'DLPRuleMatch' | extend UserId_ = tostring(RawEventData.UserId) | extend TeamName = tolower(parse_json(tostring(parse_json(tostring(RawEventData.ExchangeMetaData)).To))[0]) | extend PolicyName = tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].PolicyName) | extend RuleName = tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].RuleName) | extend SensitiveInformationTypeName = tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].ConditionsMatched)).SensitiveInformation))[0].SensitiveInformationTypeName) | join kind=inner ( CloudAppEvents | where Application == 'Microsoft Teams' | extend TeamName = tolower(RawEventData.TeamName) | extend UPN = tostring(parse_json(tostring(RawEventData.Members))[0].UPN) | extend GroupId = tostring(RawEventData.AADGroupId) | extend HasGuestUsers = tostring(parse_json(tostring(RawEventData.ParticipantInfo)).HasGuestUsers) | extend HasUnauthenticatedUsers = tostring(parse_json(tostring(RawEventData.ParticipantInfo)).HasUnauthenticatedUsers) ) on TeamName | where HasGuestUsers == 'true' or HasUnauthenticatedUsers == 'true' | project TeamName,ActionType,HasGuestUsers,HasUnauthenticatedUsers,UPN,PolicyName,RuleName,SensitiveInformationTypeName,UserId_); let individual = ( CloudAppEvents | where Application == 'Microsoft Teams' | where ActionType has 'DLPRuleMatch' | extend UPN = tostring(parse_json(tostring(parse_json(tostring(RawEventData.ExchangeMetaData)).To))[0]) | where UPN matches regex '(\\S*@\\S*.\\S*)' | extend UserId_ = tostring(RawEventData.UserId) | extend TeamName = tolower(parse_json(tostring(parse_json(tostring(RawEventData.ExchangeMetaData)).To))[0]) | extend PolicyName = tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].PolicyName) | extend RuleName = tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].RuleName) | extend SensitiveInformationTypeName = tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].ConditionsMatched)).SensitiveInformation))[0].SensitiveInformationTypeName)); let Account = ( union channel,TeamsMeeting,individual | summarize count() by UserId_,SensitiveInformationTypeName | extend Type = 'Account' | take 25); let Target = ( union channel,TeamsMeeting,individual | extend Type = 'Target' | where UPN <> '' | summarize count() by UPN,Type,SensitiveInformationTypeName | take 25); let TopChannel = ( union channel,TeamsMeeting | extend Type = 'TopChannel' | where HasGuestUsers <> '' | summarize count() by TeamName,Type,SensitiveInformationTypeName | take 25); let TopMeeting = ( union channel,TeamsMeeting | extend Type = 'TopMeeting' | where RecipientType startswith 'Guest' | summarize count() by Meeting,Type,SensitiveInformationTypeName | take 25); union Account,Target,TopChannel,TopMeeting - Name: DLPEndPointTuning DisplayName: Receive DLP tuning recommendations for Endpoints Description: This skill provides tuning recommendations for Endpoint DLP policies Settings: Target: Defender Template: |- let endpoint =( CloudAppEvents | where RawEventData.Workload has 'EndPoint' | where RawEventData.PolicyMatchInfo <> '' | extend RuleName = tostring(parse_json(tostring(RawEventData.PolicyMatchInfo)).RuleName) | extend PolicyName = tostring(parse_json(tostring(RawEventData.PolicyMatchInfo)).PolicyName) | extend SensitiveInfoTypeName = tostring(parse_json(tostring(RawEventData.SensitiveInfoTypeData))[0].SensitiveInfoTypeName) | extend TargetDomain = tostring(RawEventData.TargetDomain) | extend EnforcementMode_ = tostring(parse_json(tostring(RawEventData.EndpointMetaData)).EnforcementMode) | extend EndpointOperation_ = tostring(parse_json(tostring(RawEventData.EndpointMetaData)).EndpointOperation) | extend document = tostring(RawEventData.ObjectId) | extend UserId = tostring(RawEventData.UserId) ); let Account = ( endpoint | summarize count() by UserId | extend Type = 'Account' | take 25); let Target = ( endpoint | extend TargetDomain = tolower(RawEventData.TargetDomain) | where TargetDomain <> '' | extend Type = 'Target' | summarize count() by TargetDomain,Type,SensitiveInfoTypeName | take 25); let TargetPrinter = ( endpoint | extend TargetPrinterName = tostring(RawEventData.TargetPrinterName) | where TargetPrinterName <> '' | extend Type = 'TargetPrinter' | summarize count() by TargetPrinterName,Type,SensitiveInfoTypeName | take 25); let TargetFilePath = ( endpoint | extend TargetFilePath = tostring(RawEventData.TargetFilePath) | extend Type = 'TargetFilePath' | where TargetFilePath <> '' | summarize count() by TargetFilePath,Type,SensitiveInfoTypeName | take 25); let Device = ( endpoint | extend DeviceName_ = tostring(RawEventData.DeviceName) | extend Type = 'TopDevice' | where DeviceName_ <> '' | summarize count() by DeviceName_,Type,SensitiveInfoTypeName | take 25); let Topdocument = ( endpoint | extend Type = 'TopDoc' | extend docname = parse_path(document).Filename | where docname <> '' | summarize count() by tostring(docname),Type,SensitiveInfoTypeName | take 25); let TopSIT = ( endpoint | extend Type = 'TopSIT' | summarize count() by SensitiveInfoTypeName,Type | take 25); union Account,Topdocument,TopSIT,Target,TargetFilePath,TargetPrinter,Device - Name: DLPOCRTuning DisplayName: Receive DLP tuning recommendations for OCR Description: This skill provides tuning recommendations for OCR enabled DLP policies Settings: Target: Defender Template: |- let endpoint =( CloudAppEvents | where RawEventData.Workload has 'EndPoint' | where RawEventData.PolicyMatchInfo.PolicyName <> '' | mv-expand Sensitive = RawEventData.SensitiveInfoTypeData | extend TargetDomain = tostring(RawEventData.TargetDomain) | extend EnforcementMode_ = tostring(parse_json(tostring(RawEventData.EndpointMetaData)).EnforcementMode) | extend EndpointOperation_ = tostring(parse_json(tostring(RawEventData.EndpointMetaData)).EndpointOperation) | extend Location = tostring(parse_path(tostring(RawEventData.ObjectId)).FileType) | where Location has_any ('JPEG', 'JPG', 'PNG', 'BMP', 'TIFF','PDF')); let Exchange = ( CloudAppEvents | where ActionType has 'DLPRuleMatch' | extend Type = 'To' | where RawEventData.Workload has 'Exchange' | mv-expand PolicyDetails = RawEventData.PolicyDetails | mv-expand Rules = PolicyDetails.Rules | mv-expand Sensitive = Rules.ConditionsMatched.SensitiveInformation | extend Location = tolower(Sensitive.Location) | where Location has_any ('JPEG', 'JPG', 'PNG', 'BMP', 'TIFF','PDF')); let Teams = ( CloudAppEvents | where ActionType has 'DLPRuleMatch' | extend Type = 'To' | where RawEventData.Workload has 'MicrosoftTeams' | mv-expand PolicyDetails = RawEventData.PolicyDetails | mv-expand Rules = PolicyDetails.Rules | mv-expand Sensitive = Rules.ConditionsMatched.SensitiveInformation | extend FileSize_ = tostring(parse_json(tostring(RawEventData.ExchangeMetaData)).FileSize) | where toint(FileSize_) > 50000); let spo = ( CloudAppEvents | where ActionType has 'DLPRuleMatch' | where RawEventData.Workload has 'SharePoint' or RawEventData.Workload has 'OneDrive' | extend Location = tostring((parse_path(ObjectName)).Filename) | mv-expand PolicyDetails = RawEventData.PolicyDetails | mv-expand Rules = PolicyDetails.Rules | mv-expand Sensitive = Rules.ConditionsMatched.SensitiveInformation | where Sensitive != '' | where Location has_any ('JPEG', 'JPG', 'PNG', 'BMP', 'TIFF','PDF')); union Exchange,Teams,spo,endpoint | extend sit = (Sensitive.SensitiveInformationTypeName) | extend sit = iff(isempty(sit),Sensitive.SensitiveInfoTypeName,Sensitive.SensitiveInformationTypeName) | extend PolicyName = PolicyDetails.PolicyName | extend PolicyName = iff(isempty(PolicyName),RawEventData.PolicyMatchInfo.PolicyName,Sensitive.SensitiveInformationTypeName) | summarize UserId = make_set(tostring(RawEventData.UserId)), Detections = make_list(tostring(sit)),count(), arg_max(Timestamp, *) by Timestamp, tostring(RawEventData.UserId),tostring(Sensitive.SensitiveInformationTypeName),Location | extend To = todynamic(parse_json(tostring(parse_json(tostring(RawEventData.ExchangeMetaData)).To))[0]) | mv-expand To | extend user = split(To,'@') | project Timestamp, tostring(RawEventData.UserId),tostring(sit),Location,Subject=ObjectName,tostring(RawEventData.Workload),tostring(RawEventData.UserId),count_,user[1],PolicyName - Name: SensitiveSharePointOverSharing DisplayName: Oversharing events in SharePoint and OneDrive Description: This skill provides details about oversharing events in SharePoint and OneDrive Inputs: - Name: department Description: Specify the department for which we should return the oversharing events Required: false - Name: sitecollection Description: Specify the site collection for which we should return the oversharing events Required: false Settings: Target: Defender Template: |- let department = '{{department}}'; let sitecollection = '{{sitecollection}}'; let sharinglink = ( CloudAppEvents | where RawEventData.Workload == 'OneDrive' or RawEventData.Workload == 'SharePoint' | where RawEventData.ObjectId has sitecollection | extend Operation = tostring(RawEventData.Operation) //Filter to a smaller set of operations, add additional operations as needed | where Operation == 'AddedToSecureLink' or Operation == 'SecureLinkCreated' or Operation == 'SecureLinkUsed' or Operation == 'SharingSet' or ActionType == 'RemoveProtection' | extend Sharinglink = tostring(RawEventData.TargetUserOrGroupName) | where Sharinglink matches regex 'SharingLinks.[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}.Organization\\w*.[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}' | join kind= leftouter (CloudAppEvents | where ActionType == 'GroupRemoved' | extend TargetUserOrGroupName_ = tostring(RawEventData.TargetUserOrGroupName) | extend Sharinglink = tostring(parse_json(tostring(RawEventData.ModifiedProperties))[0].NewValue) ) on Sharinglink |extend Type = 'SharingLink' ); let group = ( CloudAppEvents | where RawEventData.Workload == 'OneDrive' or RawEventData.Workload == 'SharePoint' | where RawEventData.ObjectId has sitecollection | extend Operation = tostring(RawEventData.Operation) //Filter to a smaller set of operations, add additional operations as needed | where Operation == 'AddedToSecureLink' or Operation == 'SecureLinkCreated' or Operation == 'SecureLinkUsed' or Operation == 'SharingSet' or ActionType == 'RemoveProtection' | extend Sharinglink = tostring(RawEventData.TargetUserOrGroupName) | where Sharinglink has 'Everyone' | join kind= leftouter (CloudAppEvents | where ActionType == 'CompanyLinkRemoved' | extend TargetUserOrGroupName_ = tostring(RawEventData.TargetUserOrGroupName) ) on ObjectId | extend Type = 'Group' ); union sharinglink,group | extend UnshareOp = tostring(RawEventData1.Operation) | extend ShareTime_ = tostring(RawEventData.CreationTime) | extend UnshareTime = tostring(RawEventData1.CreationTime) | project Type,ObjectName,Sharinglink,ShareTime_,UnshareOp,UnshareTime,tostring(RawEventData.UserId) | join kind=leftouter ( IdentityInfo | where Timestamp > ago(7d) | extend AccountUpn = tolower(AccountUpn) ) on $left.RawEventData_UserId == $right.AccountUpn | where Department has department | summarize arg_max(Timestamp, *) by Type,ObjectName,Sharinglink,ShareTime_,UnshareOp,UnshareTime,RawEventData_UserId,Department,Country,City - Name: SensitiveGetExternalUploadsfromclients DisplayName: Get uploads to external websites from clients containing sensitive information Description: Fetches uploads to external websites from clients containing sensitive information Inputs: - Name: site Description: Specify the site for which the uploads are to be fetched Required: false - Name: user Description: Specify the user for which the uploads are to be fetched Required: false - Name: sitname Description: Specify the sensitive information type for which the uploads are to be fetched Required: false Settings: Target: Defender Template: |- let site = '{{site}}'; let user = '{{user}}'; let sitvar = '{{sitname}}'; CloudAppEvents | where RawEventData.Workload has 'EndPoint' | where RawEventData.TargetDomain has site | where RawEventData.UserId has user | where ActionType has 'FileUploadedToCloud' | mv-expand Sensitive = RawEventData.SensitiveInfoTypeData | where Sensitive.SensitiveInfoTypeName has sitvar | extend TargetDomain = tostring(RawEventData.TargetDomain) | extend EnforcementMode_ = tostring(parse_json(tostring(RawEventData.EndpointMetaData)).EnforcementMode) | extend EndpointOperation_ = tostring(parse_json(tostring(RawEventData.EndpointMetaData)).EndpointOperation) | extend FileName = tostring(parse_path(tostring(RawEventData.ObjectId)).Filename) | summarize count() by TargetDomain, Datatype=tostring(Sensitive.SensitiveInfoTypeName) - Name: SensitiveGetInformationaboutfilesuploadedtospecificsite DisplayName: Get the actual file uploads to specific external websites from clients containing sensitive information Description: Fetches the actual files uploads to specific external websites from clients Inputs: - Name: site Description: Specify the site for which the uploads are to be fetched Required: true - Name: sitname Description: Specify the sensitive information type for which the uploads are to be fetched Required: false - Name: document Description: Specify the document for which the uploads are to be fetched Required: false Settings: Target: Defender Template: |- let site = '{{site}}'; let sitvar = '{{sitname}}'; let document = '{{document}}'; CloudAppEvents | where RawEventData.Workload has 'EndPoint' | where RawEventData.TargetDomain has site | where ActionType has 'FileUploadedToCloud' | mv-expand Sensitive = RawEventData.SensitiveInfoTypeData | where Sensitive.SensitiveInfoTypeName has sitvar | extend TargetDomain = tostring(RawEventData.TargetDomain) | extend EnforcementMode_ = tostring(parse_json(tostring(RawEventData.EndpointMetaData)).EnforcementMode) | extend EndpointOperation_ = tostring(parse_json(tostring(RawEventData.EndpointMetaData)).EndpointOperation) | extend FileName = tostring(parse_path(tostring(RawEventData.ObjectId)).Filename) | where FileName has document | summarize count() by TargetDomain, Datatype=tostring(Sensitive.SensitiveInfoTypeName),FileName - Name: SensitiveFilesUserAccessed DisplayName: Get information about sensitive files a user has been accessing Description: Fetches information about sensitive files being accessed by users Inputs: - Name: user Description: Specify the user for which you want to get file access Required: true - Name: ISP Description: Filter the information for a specific ISP Required: false - Name: IPTag Description: Filter the information for a specific IPTag Required: false Settings: Target: Defender Template: |- let user = '{{user}}'; let ispvar = '{{ISP}}'; let iptagvar = '{{IPTag}}'; let endpoint = ( CloudAppEvents | where ISP has ispvar | extend IPTags = tostring(IPTags) | where IPTags has iptagvar | where RawEventData.UserId has user | where parse_json(tostring(RawEventData.SensitiveInfoTypeData)) != '' | where parse_json(tostring(RawEventData.SensitiveInfoTypeData)) != '[]' | extend sit = parse_json(tostring(RawEventData.SensitiveInfoTypeData)) | mv-expand sit | extend UserId = tolower(RawEventData.UserId) | extend TargetDomain = tostring(RawEventData.TargetDomain) | extend ObjectName = iff(isempty(ObjectName),tostring(RawEventData.ObjectId),ObjectName) | summarize count() by DataType=tostring(sit.SensitiveInfoTypeName),CountryCode,City,UserId,Document=ObjectName,Workload=tostring(RawEventData.Workload),TargetDomain,ISP,tostring(IPTags)); let office = ( CloudAppEvents | where ActionType has 'DLPRuleMatch' | where RawEventData.UserId has user | extend sit = parse_json(tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].ConditionsMatched)).SensitiveInformation)) | where sit != '' | mv-expand sit | extend UserId = tolower(RawEventData.UserId) | extend sit_SensitiveInfoTypeName = tostring(sit.SensitiveInformationTypeName) | join kind=inner (CloudAppEvents | where ActionType !has 'DLPRuleMatch' | where ISP has ispvar | extend IPTags = tostring(IPTags) | where IPTags has iptagvar | project ISP, ObjectId,IPTags,ActionType ) on ObjectId | summarize count() by DataType=sit_SensitiveInfoTypeName,UserId,Document=ObjectName,Workload=tostring(RawEventData.Workload),ISP=ISP1,IPTags=tostring(IPTags1)); union endpoint,office | project DataType,CountryCode,City,UserId,Document,Workload,TargetDomain,Count=count_,ISP,tostring(IPTags) - Name: SensitivefilesaccessedbyCompromisedusers DisplayName: Get sensitive documents that are accessed by compromised users Description: Fetches sensitive documents that are accessed by compromised users Inputs: - Name: user Description: Specify the user for which the sensitive content is to be fetched Required: false - Name: document Description: Specify the document to identify to map to possible compromised users Required: false - Name: ISP Description: Filter the information for a specific ISP Required: false - Name: IPTag Description: Filter the information for a specific IPTag Required: false Settings: Target: Defender Template: |- let ispvar = '{{ISP}}'; let iptagvar = '{{IPTag}}'; let user = '{{user}}'; let document = '{{document}}'; let AlertEvidence = (AlertEvidence | where Timestamp > ago(31d) //| where ProcessCommandLine =='' | extend upnsuffix = todynamic (AdditionalFields).UPNSuffix | extend upn1 = iff(isempty(todynamic (AdditionalFields).Recipient),todynamic (AdditionalFields).Upn,todynamic (AdditionalFields).Recipient) | extend user = parse_json(tostring(todynamic(AdditionalFields).Account)) | extend upn2 = strcat(user.Name,'@',user.UPNSuffix) | extend upn3 = iff(isempty(user.Name),upn1,upn2) | extend upn4 = strcat(AccountName,'@',AccountDomain) | extend upn5 = strcat(AccountName,'@',upnsuffix) | extend upn6 = iff(isempty(upnsuffix),upn4,upn5) | extend upn = iff(isempty(upn3),upn6,upn3) | extend upn = tolower(upn) | distinct upn,ThreatFamily,Categories | extend d = bag_pack("ThreatFamily", ThreatFamily, "Categories", Categories) | summarize AttackDetail = make_list(strcat(d)) by upn); let endpoint = ( AlertEvidence | where upn has tolower(user) | join kind=inner ( CloudAppEvents | where ISP has ispvar | extend IPTags = tostring(IPTags) | where IPTags has iptagvar | where parse_json(tostring(RawEventData.SensitiveInfoTypeData)) != '' | where parse_json(tostring(RawEventData.SensitiveInfoTypeData)) != '[]' | extend sit = parse_json(tostring(RawEventData.SensitiveInfoTypeData)) | mv-expand sit | extend UserId = tolower(RawEventData.UserId) | extend TargetDomain = tostring(RawEventData.TargetDomain) | extend ObjectName = iff(isempty(ObjectName),tostring(RawEventData.ObjectId),ObjectName) | where ObjectName has document | summarize count() by tostring(sit.SensitiveInfoTypeName),CountryCode,City,UserId,ObjectName,tostring(RawEventData.Workload),TargetDomain,ISP,tostring(IPTags) ) on $left.upn == $right.UserId); let office = ( AlertEvidence | where upn has tolower(user) | join kind=inner ( CloudAppEvents | where ActionType has 'DLPRuleMatch' | extend sit = parse_json(tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].ConditionsMatched)).SensitiveInformation)) | where sit != '' | mv-expand sit | extend UserId = tolower(RawEventData.UserId) | extend sit_SensitiveInfoTypeName = tostring(sit.SensitiveInformationTypeName) | where url_decode(ObjectName) has document | join kind=inner (CloudAppEvents | where ActionType !has 'DLPRuleMatch' | where ISP has ispvar | extend IPTags = tostring(IPTags) | where IPTags has iptagvar | project ISP, ObjectId,IPTags,ActionType ) on ObjectId | summarize count() by DataType=sit_SensitiveInfoTypeName,UserId,Document=ObjectName,Workload=tostring(RawEventData.Workload),ISP=ISP1,IPTags=tostring(IPTags1)) on $left.upn == $right.UserId); union endpoint,office | join kind=leftouter ( IdentityInfo | where Timestamp > ago(7d) | extend AccountUpn = tolower(AccountUpn) ) on $left.upn == $right.AccountUpn | summarize arg_max(Timestamp, *) by sit_SensitiveInfoTypeName,CountryCode,City,UserId,ObjectName,RawEventData_Workload,TargetDomain,tostring(AttackDetail) | summarize sum(count_) by DataType=sit_SensitiveInfoTypeName,CountryCode,City,UserId,upn,Department,Document=ObjectName,Workload=RawEventData_Workload,TargetDomain,AttackDetail=tostring(AttackDetail),ISP,tostring(IPTags) - Name: SensitiveEmailAccessactivitybyCVEorVendororNetwork DisplayName: Get the sensitive file activity based on CVE,Vendor,ISP or IPTags for Exchange, email content. Description: Fetches the sensitive email activity correlated with CVE or Vendor Inputs: - Name: CVE Description: The CVE to investigate across the file activity Required: false - Name: Vendor Description: The vendor to investigate across the file activity Required: false - Name: ISP Description: Filter the information for a specific ISP Required: false - Name: IPTag Description: Filter the information for a specific IPTag Required: false - Name: sit Description: Filter the information for a specific Sensitivity Information Type Required: false Settings: Target: Defender Template: |- let cveid1 = '{{CVE}}'; let vendor = '{{Vendor}}'; let ispvar = '{{ISP}}'; let iptagvar = '{{IPTag}}'; let sitvar = '{{sit}}'; CloudAppEvents | where Timestamp > ago(30d) | where tostring(RawEventData.Workload) == "Exchange" | where ActionType == "DlpRuleMatch" | extend sit = parse_json(tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].ConditionsMatched)).SensitiveInformation)) | where sit != '' | mv-expand sit | where tostring(sit.SensitiveInformationTypeName) has sitvar | project InternetMessageId=ObjectId,sit,Subject = ObjectName | join kind=inner ( CloudAppEvents | where tostring(RawEventData.Operation) == "MailItemsAccessed" | where tolower(ISP) has tolower(ispvar) | extend IPtagsv = iff(isnull(IPTags),'NotSet',IPTags) | extend IPTags = tostring(IPTags) | where IPtagsv has iptagvar | mv-expand RawEventData.Folders | mv-expand FolderItem = RawEventData_Folders.FolderItems | extend InternetMessageId = tostring(FolderItem.InternetMessageId) | extend SensitivityLabel = tostring(FolderItem.Sensitivity) ) on $left.InternetMessageId == $right.InternetMessageId | join kind=leftouter ( DeviceInfo | summarize by DeviceId,PublicIP,DeviceName ) on $left.IPAddress == $right.PublicIP | summarize arg_max(Timestamp, *) by UserId = tolower(RawEventData.UserId),InternetMessageId,ISP,tostring(IPTags),DeviceId | join kind = leftouter ( DeviceTvmSoftwareVulnerabilities | extend cveid1 = iff(isempty(cveid1),'NotSet',cveid1) | extend vendor = iff(isempty(vendor),'NotSet',vendor) | where CveId has cveid1 or SoftwareVendor has vendor ) on DeviceId | join kind=leftouter ( IdentityInfo | where Timestamp > ago(7d) | extend AccountUpn = tolower(AccountUpn) ) on $left.UserId == $right.AccountUpn | summarize count = count() by DataType=tostring(sit.SensitiveInformationTypeName),SensitivityLabel,DeviceName,Department,SoftwareName,SoftwareVersion,ISP,tostring(IPTags),CveId - Name: SensitiveEmailsaccessedbyusers DisplayName: Who accessed the emails containing sensitive information and from where Description: Fetches the sensitive information type,label user and the email accessed as well as ISP, Device information Inputs: - Name: user Description: Specify the user id for which the email access is to be fetched Required: false - Name: subject Description: Specify the subject for which the email access is to be fetched Required: false - Name: InternetMessageId Description: Specify the InternetMessageId for which the email access is to be fetched Required: false Settings: Target: Defender Template: |- let user = '{{user}}'; let subject = '{{subject}}'; let InternetMessageId = '{{InternetMessageId}}'; CloudAppEvents | where tostring(RawEventData.Workload) == "Exchange" | where ActionType == "DlpRuleMatch" | where tolower(RawEventData.UserId) has tolower(user) | where ObjectId has InternetMessageId | where tolower(ObjectName) has tolower(subject) | extend sit = parse_json(tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].ConditionsMatched)).SensitiveInformation)) | where sit != '' | mv-expand sit | project InternetMessageId=ObjectId,sit,Subject = ObjectName | join kind=inner ( CloudAppEvents | where tostring(RawEventData.Operation) == "MailItemsAccessed" | mv-expand RawEventData.Folders | mv-expand FolderItem = RawEventData_Folders.FolderItems | extend InternetMessageId = tostring(FolderItem.InternetMessageId) | extend SensitivityLabel = tostring(FolderItem.Sensitivity) ) on $left.InternetMessageId == $right.InternetMessageId | join kind=leftouter ( DeviceInfo | summarize by DeviceId,PublicIP,DeviceName ) on $left.IPAddress == $right.PublicIP | summarize arg_max(Timestamp, *) by UserId = tostring(RawEventData.UserId),InternetMessageId,ISP,tostring(IPTags),DeviceName | project AccountType,Subject,DataType=sit.SensitiveInformationTypeName,SensitivityLabel,MailboxOwnerUPN = tostring(RawEventData.MailboxOwnerUPN),UserId = tostring(RawEventData.UserId),ISP,IPTags,CountryCode,UserAgent,DeviceName - Name: DLPInformationaboutforwarding DisplayName: Was the email forwarded from the user's mailbox Description: Fetches the full information about a message including if the message was forwarded. Inputs: - Name: user Description: Specify the user for which the email forwarding information is to be fetched Required: false - Name: subject Description: Specify the subject for which the email forwarding information is to be fetched Required: false - Name: InternetMessageId Description: Specify the InternetMessageId for which the email forwarding information is to be fetched Required: false Settings: Target: Defender Template: |- let user = '{{user}}'; let subject = '{{subject}}'; let InternetMessageId = '{{InternetMessageId}}'; CloudAppEvents | where RawEventData.Workload has 'Exchange' | where tolower(RawEventData.UserId) has tolower(user) | where ActionType has "DLPRuleMatch" | where ObjectId has InternetMessageId | join kind=inner ( EmailEvents | where Subject has subject | where InternetMessageId has InternetMessageId | extend ObjectId = InternetMessageId ) on ObjectId | summarize by Subject,RecipientEmailAddress,InternetMessageId - Name: SensitiveUnlabelledDocumentOperations DisplayName: Show unlabelled document operations across departments in contrast to labelled Description: Fetches the unlabelled document operations across departments in contrast to labelled Inputs: - Name: department Description: Specify the department for which the unlabelled document operations are to be fetched Required: false Settings: Target: Defender Template: |- let department = '{{department}}'; let content = ( CloudAppEvents | where Timestamp > ago(30d) | where ActionType in ('FileCopiedToClipboard', 'FileCopiedToNetworkShare', 'FileCopiedToRemoteDesktopSession', 'FileCopiedToRemovableMedia', 'FilePrinted', 'FileSensitivityLabelApplied', 'FileUploadedToCloud','FileUploaded','SharingSet', 'FileRead','FileRenamed', 'MipLabel', 'SensitivityLabelApplied', 'SensitivityLabeledFileOpened', 'SensitivityLabelRemoved', 'SensitivityLabelUpdated', 'ArchiveCreated', 'FileAccessedByUnallowedApp', 'FileArchived','FileAccessed', 'FileCreatedOnNetworkShare', 'FileCreatedOnRemovableMedia', 'FileModified', 'RemoveProtection','FileTransferredByBluetooth', 'WebpagePrinted', 'WebpageCopiedToClipboard', 'WebpageSavedToLocal', 'PastedToBrowser') | where Application <> 'Microsoft Exchange Online' | extend ObjectId_ = tostring(RawEventData.ObjectId) | where ObjectId_ !has 'AppData' | where ActivityType <> 'Send' | extend LabelGUID1 = parse_json(tostring(RawEventData.SensitivityLabelEventData)).SensitivityLabelId | extend LabelGUID2 = iff(isempty(tostring(RawEventData.LabelId)), LabelGUID1, tostring(RawEventData.LabelId)) | extend LabelGUID3 = iff(isempty(tostring(RawEventData.SensitivityLabelId)), LabelGUID2, tostring(RawEventData.SensitivityLabelId)) | extend OldSensitivityLabelId = tostring(parse_json(tostring(RawEventData.SensitivityLabelEventData)).OldSensitivityLabelId) | extend LabelGUID = iff(isempty(tostring(LabelGUID3)),OldSensitivityLabelId, tostring(LabelGUID3)) | extend userid= tolower(RawEventData.UserId) ); let unlabelledcontent = ( content | where LabelGUID =='' |summarize count() by userid | extend Type = 'UnLabelledOps' ); let labelledcontent=( content | where LabelGUID !='' | summarize count() by userid | extend Type = 'LabelledOps'); union unlabelledcontent,labelledcontent | join kind=leftouter ( IdentityInfo | where Timestamp > ago(7d) | extend AccountUpn = tolower(AccountUpn) ) on $left.userid == $right.AccountUpn | where Department has department | summarize arg_max(Timestamp, *) by userid,Type | summarize sum(count_) by Department,Type - Name: SensitiveInformationOperationsbyDepartment DisplayName: Show Sensitive document operations across based on Sensitive Information Type, department and location Description: Fetches the sensitive document operations across based on Sensitive Information Type, department and location Inputs: - Name: department Description: Specify the department for which the sensitive document operations are to be fetched Required: false - Name: sitname Description: Specify the sensitive information type for which the sensitive document operations are to be fetched Required: false Settings: Target: Defender Template: |- let department = '{{department}}'; let sitvar = '{{sitname}}'; let endpoint = ( CloudAppEvents | where parse_json(tostring(RawEventData.SensitiveInfoTypeData)) != '' | where parse_json(tostring(RawEventData.SensitiveInfoTypeData)) != '[]' | extend sit = parse_json(tostring(RawEventData.SensitiveInfoTypeData)) | mv-expand sit | where sit.SensitiveInfoTypeName has sitvar | extend UserId = tolower(RawEventData.UserId) | extend TargetDomain = tostring(RawEventData.TargetDomain) | extend ObjectName = iff(isempty(ObjectName),tostring(RawEventData.ObjectId),ObjectName) | summarize count() by Datatype=tostring(sit.SensitiveInfoTypeName),CountryCode,City,UserId,ObjectName,tostring(RawEventData.Workload),TargetDomain); let office = ( CloudAppEvents | where ActionType has 'DLPRuleMatch' | extend sit = parse_json(tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].ConditionsMatched)).SensitiveInformation)) | where sit != '' | mv-expand sit | extend UserId = tolower(RawEventData.UserId) | extend sit_SensitiveInfoTypeName = tostring(sit.SensitiveInformationTypeName) | join kind=inner (CloudAppEvents | where ActionType !has 'DLPRuleMatch' | project ISP, ObjectId,IPTags,ActionType,CountryCode,City | where CountryCode != '' ) on ObjectId | extend CountryCode = CountryCode1 | extend City = City1 | summarize count() by Datatype=sit_SensitiveInfoTypeName,UserId,ObjectName,tostring(RawEventData.Workload),CountryCode,City); union endpoint,office | join kind=inner ( IdentityInfo | where Timestamp > ago(7d) | extend AccountUpn = tolower(AccountUpn) ) on $left.UserId == $right.AccountUpn | where Department has department | summarize arg_max(Timestamp, *) by Datatype,CountryCode,City | summarize sum(count_) by Datatype,CountryCode,City,Department - Name: SensitiveLabelledActivitybyCVEorVendor DisplayName: Get the sensitivity label file activity based on CVE or Vendor Description: Fetches the sensitivity label file activity happening on the Device associated with the CVE or Vendor Inputs: - Name: CVE Description: The CVE to investigate across the file activity Required: false - Name: Vendor Description: The vendor to investigate across the file activity Required: false - Name: ISP Description: Filter the information for a specific ISP Required: false - Name: IPTag Description: Filter the information for a specific IPTag Required: false Settings: Target: Defender Template: |- let cveid1 = '{{CVE}}'; let vendor = '{{Vendor}}'; let ispvar = '{{ISP}}'; let iptagvar = '{{IPTag}}'; CloudAppEvents | where RawEventData.MDATPDeviceId != '' | where ISP has ispvar | extend IPTags = tostring(IPTags) | where IPTags has iptagvar | where Timestamp > ago(31d) | where ActionType in ('FileCopiedToClipboard', 'FileCopiedToNetworkShare', 'FileCopiedToRemoteDesktopSession', 'FileCopiedToRemovableMedia', 'FilePrinted', 'FileSensitivityLabelApplied', 'FileUploadedToCloud','FileUploaded','SharingSet', 'FileRead','FileRenamed', 'MipLabel', 'SensitivityLabelApplied', 'SensitivityLabeledFileOpened', 'SensitivityLabelRemoved', 'SensitivityLabelUpdated', 'ArchiveCreated', 'FileAccessedByUnallowedApp', 'FileArchived','FileAccessed', 'FileCreatedOnNetworkShare', 'FileCreatedOnRemovableMedia', 'FileModified', 'RemoveProtection','FileTransferredByBluetooth', 'WebpagePrinted', 'WebpageCopiedToClipboard', 'WebpageSavedToLocal', 'PastedToBrowser','FileSensitivityLabelChanged','FileDownloaded','SensitivityLabelPolicyMatched','SharingLinkCreated','SharingLinkUsed') | where Application <> 'Microsoft Exchange Online' | extend ObjectId_ = tostring(RawEventData.ObjectId) | where ObjectId_ !has 'AppData' | where ActivityType <> 'Send' | extend LabelGUID1 = parse_json(tostring(RawEventData.SensitivityLabelEventData)).SensitivityLabelId | extend LabelGUID2 = iff(isempty(tostring(RawEventData.LabelId)), LabelGUID1, tostring(RawEventData.LabelId)) | extend LabelGUID3 = iff(isempty(tostring(RawEventData.SensitivityLabelId)), LabelGUID2, tostring(RawEventData.SensitivityLabelId)) | extend OldSensitivityLabelId = tostring(parse_json(tostring(RawEventData.SensitivityLabelEventData)).OldSensitivityLabelId) | extend LabelGUID = iff(isempty(tostring(LabelGUID3)),OldSensitivityLabelId, tostring(LabelGUID3)) | where LabelGUID !='' | extend userid = tolower(RawEventData.UserId) | extend DeviceId = tostring(RawEventData.MDATPDeviceId) | extend AppUsed = tostring(RawEventData.Application) | join kind = inner ( DeviceTvmSoftwareVulnerabilities | extend cveid1 = iff(isempty(cveid1),'NotSet',cveid1) | extend vendor = iff(isempty(vendor),'NotSet',vendor) | where CveId has cveid1 or SoftwareVendor has vendor ) on DeviceId | summarize count() by LabelGUID,City,userid,CountryCode,ISP,tostring(IPTags),DeviceName,AppUsed | join kind=leftouter ( IdentityInfo | where Timestamp > ago(7d) | extend AccountUpn = tolower(AccountUpn) ) on $left.userid == $right.AccountUpn | summarize arg_max(Timestamp, *) by LabelGUID,Department,Country,userid,City,DeviceName,ISP,AppUsed,tostring(IPTags) | summarize sum(count_) by LabelGUID,Department,City,CountryCode,userid,ISP,tostring(IPTags),DeviceName,AppUsed - Name: SensitiveLabelledActivityoutliers DisplayName: Get the sensitivity label file activity that are outliers or anomalies Description: Fetches the sensitivity label file activity happening and identifies the outliers and anomalies Inputs: - Name: ISP Description: Filter the information for a specific ISP Required: false - Name: IPTag Description: Filter the information for a specific IPTag Required: false Settings: Target: Defender Template: |- let ispvar = '{{ISP}}'; let iptagvar = '{{IPTag}}'; CloudAppEvents | where Timestamp > ago(14d) | where RawEventData.MDATPDeviceId != '' | where ISP has ispvar | extend IPTags = tostring(IPTags) | where IPTags has iptagvar | where ActionType in ('FileCopiedToClipboard', 'FileCopiedToNetworkShare', 'FileCopiedToRemoteDesktopSession', 'FileCopiedToRemovableMedia', 'FilePrinted', 'FileSensitivityLabelApplied', 'FileUploadedToCloud','FileUploaded','SharingSet', 'FileRead','FileRenamed', 'MipLabel', 'SensitivityLabelApplied', 'SensitivityLabeledFileOpened', 'SensitivityLabelRemoved', 'SensitivityLabelUpdated', 'ArchiveCreated', 'FileAccessedByUnallowedApp', 'FileArchived','FileAccessed', 'FileCreatedOnNetworkShare', 'FileCreatedOnRemovableMedia', 'FileModified', 'RemoveProtection','FileTransferredByBluetooth', 'WebpagePrinted', 'WebpageCopiedToClipboard', 'WebpageSavedToLocal', 'PastedToBrowser','FileSensitivityLabelChanged','FileDownloaded','SensitivityLabelPolicyMatched','SharingLinkCreated','SharingLinkUsed') | where Application <> 'Microsoft Exchange Online' | extend ObjectId_ = tostring(RawEventData.ObjectId) | where ObjectId_ !has 'AppData' | where ActivityType <> 'Send' | extend LabelGUID1 = parse_json(tostring(RawEventData.SensitivityLabelEventData)).SensitivityLabelId | extend LabelGUID2 = iff(isempty(tostring(RawEventData.LabelId)), LabelGUID1, tostring(RawEventData.LabelId)) | extend LabelGUID3 = iff(isempty(tostring(RawEventData.SensitivityLabelId)), LabelGUID2, tostring(RawEventData.SensitivityLabelId)) | extend OldSensitivityLabelId = tostring(parse_json(tostring(RawEventData.SensitivityLabelEventData)).OldSensitivityLabelId) | extend LabelGUID = iff(isempty(tostring(LabelGUID3)),OldSensitivityLabelId, tostring(LabelGUID3)) | where LabelGUID !='' | extend userid = tolower(RawEventData.UserId) | extend DeviceId = tostring(RawEventData.MDATPDeviceId) | extend AppUsed = tostring(RawEventData.Application) | summarize EventCount=count() by userid,LabelGUID,ISP,tostring(IPTags),AppUsed, bin(Timestamp,30m) | order by Timestamp | summarize EventCount=make_list(EventCount),TimeGenerated=make_list(Timestamp) by userid,ISP,tostring(IPTags),AppUsed | extend outliers=series_decompose_anomalies(EventCount) | mv-expand TimeGenerated, EventCount, outliers | where outliers == 1 | summarize aggregate=sum(todecimal(EventCount)) by userid,ISP,tostring(IPTags),AppUsed - Name: SensitiveEndpointactivitybyCVEorVendor DisplayName: Get the sensitive file activity based on CVE or Vendor Description: Fetches the sensitive file activity happening on the Device associated with the CVE or Vendor Inputs: - Name: CVE Description: The CVE to investigate across the file activity Required: false - Name: Vendor Description: The vendor to investigate across the file activity Required: false - Name: ISP Description: Filter the information for a specific ISP Required: false - Name: IPTag Description: Filter the information for a specific IPTag Required: false - Name: sit Description: Filter the information for a specific Sensitivity Information Type Required: false Settings: Target: Defender Template: |- let cveid = '{{CVE}}'; let vendor = '{{Vendor}}'; let ispvar = '{{ISP}}'; let iptagvar = '{{IPTag}}'; let sitvar = '{{sit}}'; DeviceTvmSoftwareVulnerabilities | where CveId has cveid | where SoftwareVendor has vendor | join kind = inner ( CloudAppEvents | where ISP has ispvar | extend IPTags = tostring(IPTags) | where IPTags has iptagvar | where parse_json(tostring(RawEventData.SensitiveInfoTypeData)) != "" | where parse_json(tostring(RawEventData.SensitiveInfoTypeData)) != "[]" | extend sit = parse_json(tostring(RawEventData.SensitiveInfoTypeData)) | mv-expand sit | extend UserId = tolower(RawEventData.UserId) | extend SensitiveInfoTypeName = tostring(sit.SensitiveInfoTypeName) | where SensitiveInfoTypeName has sitvar | extend document = tostring(RawEventData.ObjectId) | extend DeviceId = tostring(RawEventData.MDATPDeviceId) | extend AppUsed = tostring(RawEventData.Application) ) on DeviceId | summarize count = count() by SensitiveInfoTypeName,DeviceName,CountryCode,SoftwareName,SoftwareVersion,AppUsed,ISP,tostring(IPTags) - Name: SensitiveEndpointactivitybyNetwork DisplayName: Get the sensitive file activity based on network ISP or IPTags Description: Fetches the sensitive file activity happening on the Device associated with the network ISP or IPTags Inputs: - Name: Vendor Description: The vendor to investigate across the file activity Required: false - Name: ISP Description: Filter the information for a specific ISP Required: false - Name: IPTag Description: Filter the information for a specific IPTag Required: false - Name: sit Description: Filter the information for a specific Sensitivity Information Type Required: false Settings: Target: Defender Template: |- let vendor = '{{Vendor}}'; let ispvar = '{{ISP}}'; let iptagvar = '{{IPTag}}'; let sitvar = '{{sit}}'; CloudAppEvents | where ISP has ispvar | extend IPTags = tostring(IPTags) | where IPTags has iptagvar | where parse_json(tostring(RawEventData.SensitiveInfoTypeData)) != "" | where parse_json(tostring(RawEventData.SensitiveInfoTypeData)) != "[]" | extend sit = parse_json(tostring(RawEventData.SensitiveInfoTypeData)) | mv-expand sit | extend UserId = tolower(RawEventData.UserId) | extend SensitiveInfoTypeName = tostring(sit.SensitiveInfoTypeName) | where SensitiveInfoTypeName has sitvar | extend document = tostring(RawEventData.ObjectId) | extend DeviceId = tostring(RawEventData.MDATPDeviceId) | extend AppUsed = tostring(RawEventData.Application) | summarize count = count() by SensitiveInfoTypeName,CountryCode,AppUsed,ISP,tostring(IPTags),DeviceId - Name: SensitiveContentAnomalies DisplayName: Get Sensitive content anomalies from the log stream Description: Fetches the Sensitive content anomalies from the log stream Inputs: - Name: ISP Description: Filter the information for a specific ISP Required: false - Name: IPTag Description: Filter the information for a specific IPTag Required: false Settings: Target: Defender Template: |- let ispvar = '{{ISP}}'; let iptagvar = '{{IPTag}}'; let min_peak_t=now(-30d); let max_peak_t=now(-14d); let min_baseline_t=now(-13d); let max_baseline_t=now(-1d); let splitime=(max_baseline_t+min_peak_t)/2.0; CloudAppEvents | where ISP has ispvar | extend IPTags = tostring(IPTags) | where IPTags has iptagvar | where parse_json(tostring(RawEventData.SensitiveInfoTypeData)) != "" | where parse_json(tostring(RawEventData.SensitiveInfoTypeData)) != "[]" | extend sit = parse_json(tostring(RawEventData.SensitiveInfoTypeData)) | mv-expand sit | extend SensitiveInfoTypeName = tostring(sit.SensitiveInfoTypeName) | extend UserId = tostring(RawEventData.UserId) | extend document = tostring(RawEventData.ObjectId) | project Timestamp,document,UserId,SensitiveInfoTypeName,DeviceType,ISP,IPTags | where (Timestamp between(min_baseline_t..max_baseline_t)) or (Timestamp between(min_peak_t..max_peak_t)) | extend AB=iff(Timestamp > splitime, 'Anomaly', 'Baseline') | evaluate diffpatterns(AB, 'Anomaly', 'Baseline') - Name: SensitiveEndpointinternetfacing DisplayName: Get the sensitive file activity for devices that are internet facing Description: Fetches the sensitive file activity happening on the Devices that are internet facing Inputs: - Name: sit Description: Filter the information for a specific Sensitivity Information Type Required: false Settings: Target: Defender Template: |- let sitvar = '{{sit}}'; DeviceInfo | where Timestamp > ago(7d) | where IsInternetFacing | extend InternetFacingInfo = AdditionalFields | extend InternetFacingReason = extractjson("$.InternetFacingReason", InternetFacingInfo, typeof(string)), InternetFacingLocalPort = extractjson("$.InternetFacingLocalPort", InternetFacingInfo, typeof(int)), InternetFacingScannedPublicPort = extractjson("$.InternetFacingPublicScannedPort", InternetFacingInfo, typeof(int)), InternetFacingScannedPublicIp = extractjson("$.InternetFacingPublicScannedIp", InternetFacingInfo, typeof(string)), InternetFacingLocalIp = extractjson("$.InternetFacingLocalIp", InternetFacingInfo, typeof(string)), InternetFacingTransportProtocol=extractjson("$.InternetFacingTransportProtocol", InternetFacingInfo, typeof(string)), InternetFacingLastSeen = extractjson("$.InternetFacingLastSeen", InternetFacingInfo, typeof(datetime)) | summarize arg_max(Timestamp, *) by DeviceId | project DeviceId,InternetFacingInfo,DeviceName | join kind = inner ( CloudAppEvents | where Timestamp > ago(31d) | where parse_json(tostring(RawEventData.SensitiveInfoTypeData)) != "" | where parse_json(tostring(RawEventData.SensitiveInfoTypeData)) != "[]" | extend sit = parse_json(tostring(RawEventData.SensitiveInfoTypeData)) | mv-expand sit | extend UserId = tolower(RawEventData.UserId) | extend SensitiveInfoTypeName = tostring(sit.SensitiveInfoTypeName) | where SensitiveInfoTypeName has sitvar | extend document = tostring(RawEventData.ObjectId) | extend DeviceId = tostring(RawEventData.MDATPDeviceId) | extend AppUsed = tostring(RawEventData.Application) ) on DeviceId | summarize count = count() by SensitiveInfoTypeName,DeviceName,CountryCode,InternetFacingInfo,AppUsed - Name: SensitiveContentSummaryofApplications DisplayName: Get Applications that are accessing sensitive content Description: Fetches the Applications that are accessing sensitive content Settings: Target: Defender Template: |- CloudAppEvents | where parse_json(tostring(RawEventData.SensitiveInfoTypeData)) != "" | where parse_json(tostring(RawEventData.SensitiveInfoTypeData)) != "[]" | extend sit = parse_json(tostring(RawEventData.SensitiveInfoTypeData)) | mv-expand sit | extend UserId = tolower(RawEventData.UserId) | extend SensitiveInfoTypeName = tostring(sit.SensitiveInfoTypeName) | extend document = tostring(RawEventData.ObjectId) | extend DeviceId = tostring(RawEventData.MDATPDeviceId) | extend AppUsed = tolower(RawEventData.Application) | where AppUsed !="" | summarize by AppUsed,DeviceId,SensitiveInfoTypeName | join kind=inner ( DeviceProcessEvents | where Timestamp > ago(7d) | extend AppUsed = tolower(FileName) | summarize by AppUsed,SHA256,ProcessVersionInfoCompanyName,ProcessVersionInfoProductName,DeviceId ) on AppUsed,DeviceId | summarize count() by AppUsed,SHA256,ProcessVersionInfoCompanyName,ProcessVersionInfoProductName | sort by count_ - Name: SensitiveContentApplicationdetail DisplayName: Get the Sensitive data types that an Application is accessing Description: Fetches the Sensitive data types that and Application is accessing Inputs: - Name: ApplicationName Description: Filter the information for a specific Application Required: true - Name: SensitiveInfoTypeName Description: Filter the information for a specific Sensitive Information Type Required: false Settings: Target: Defender Template: |- let sitvar = '{{SensitiveInfoTypeName}}'; let app = '{{ApplicationName}}'; CloudAppEvents | where parse_json(tostring(RawEventData.SensitiveInfoTypeData)) != "" | where parse_json(tostring(RawEventData.SensitiveInfoTypeData)) != "[]" | extend sit = parse_json(tostring(RawEventData.SensitiveInfoTypeData)) | mv-expand sit | extend UserId = tolower(RawEventData.UserId) | extend SensitiveInfoTypeName = tostring(sit.SensitiveInfoTypeName) | where SensitiveInfoTypeName has sitvar | extend document = tostring(RawEventData.ObjectId) | extend DeviceId = tostring(RawEventData.MDATPDeviceId) | extend AppUsed = tolower(RawEventData.Application) | where AppUsed !="" | where AppUsed has tolower(app) | summarize by AppUsed,DeviceId,SensitiveInfoTypeName | join kind=inner ( DeviceProcessEvents | where Timestamp > ago(7d) | extend AppUsed = tolower(FileName) | summarize by AppUsed,SHA256,ProcessVersionInfoCompanyName,ProcessVersionInfoProductName,DeviceId ) on AppUsed,DeviceId | summarize count() by AppUsed,SHA256,ProcessVersionInfoCompanyName,ProcessVersionInfoProductName,SensitiveInfoTypeName | sort by count_ - Name: SensitiveContentAppNetworkActivity DisplayName: Get Application network activity for apps accessing sensitive content Description: Fetches the Application network activity for apps accessing sensitive content Inputs: - Name: ApplicationName Description: Filter the information for a specific Application Required: true - Name: SensitiveInfoTypeName Description: Filter the information for a specific Sensitive Information Type Required: false Settings: Target: Defender Template: |- let sitvar = '{{SensitiveInfoTypeName}}'; let app = '{{ApplicationName}}'; let corequery = ( CloudAppEvents | where parse_json(tostring(RawEventData.SensitiveInfoTypeData)) != "" | where parse_json(tostring(RawEventData.SensitiveInfoTypeData)) != "[]" | extend sit = parse_json(tostring(RawEventData.SensitiveInfoTypeData)) | mv-expand sit | extend UserId = tolower(RawEventData.UserId) | extend SensitiveInfoTypeName = tostring(sit.SensitiveInfoTypeName) | where SensitiveInfoTypeName has sitvar | extend document = tostring(RawEventData.ObjectId) | extend DeviceId = tostring(RawEventData.MDATPDeviceId) | extend AppUsed = tolower(RawEventData.Application) | where AppUsed == tolower(app) | where AppUsed !="" | summarize count() by AppUsed,SensitiveInfoTypeName,DeviceId | join kind=inner ( DeviceNetworkEvents | extend AppUsed = tolower(InitiatingProcessFileName)) on AppUsed,DeviceId); corequery | summarize count() by DeviceId,AppUsed,SensitiveInfoTypeName,RemotePort,RemoteUrl,RemoteIP,LocalIPType,RemoteIPType,DeviceName,InitiatingProcessSHA256 - Name: Getemailbyrecipient DisplayName: Get email messages by recipient Description: Fetches the email messages by recipient Inputs: - Name: Recipient Description: Filter the information for a specific Recipient Required: true Settings: Target: Defender Template: |- let Recipient = '{{Recipient}}'; EmailEvents | where RecipientEmailAddress has Recipient | project SenderMailFromAddress,Subject,RecipientEmailAddress,AttachmentCount,UrlCount,InternetMessageId - Name: MicrosoftCopilotActivityRiskyUser DisplayName: Get the Microsoft Copilot activity labelled and unlabelled as well as data type activity for Risky Users Description: Fetches the Microsoft Copilot activity labelled and unlabelled as well as data type activity for Risky Users Settings: Target: Defender Template: |- CloudAppEvents | where Timestamp > ago(30d) | where ActionType has 'CopilotInteraction' | extend AccessedResources = iif(array_length(RawEventData.CopilotEventData.AccessedResources)==0, todynamic('Empty:Field') , RawEventData.CopilotEventData.AccessedResources) | mv-expand AccessedResources | extend Content = url_decode(tostring(AccessedResources.SiteUrl)) | extend ObjectName = tolower(replace_string(Content,'?web=1','')) | extend UserId = tostring(RawEventData.UserId) | extend LabelGUID = tostring(AccessedResources.SensitivityLabelId) | summarize arg_max(Timestamp, *) by UserId,ObjectName | join kind=leftouter (CloudAppEvents | where ActionType has 'DLPRuleMatch' | extend sit = parse_json(tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].ConditionsMatched)).SensitiveInformation)) | where sit != '' | mv-expand sit | extend UserId = tolower(RawEventData.UserId) | extend ObjectName = tolower(url_decode(tostring(ObjectName))) | where ObjectName != '' | extend sit_SensitiveInfoTypeName = tostring(sit.SensitiveInformationTypeName) | summarize by sit_SensitiveInfoTypeName,ObjectName | summarize SensitiveInformationTypes = make_list(strcat(sit_SensitiveInfoTypeName)) by ObjectName) on ObjectName | extend AISystemPlugin_ = tostring(parse_json(tostring(parse_json(tostring(RawEventData.CopilotEventData)).AISystemPlugin))) | extend ModelName_ = tostring(parse_json(tostring(parse_json(tostring(RawEventData.CopilotEventData)).ModelTransparencyDetails))[0].ModelName) | extend Id_ = tostring(RawEventData.Id) | summarize AccessedSite = make_list(strcat(ObjectName)) by UserId,Id_,LabelGUID,tostring(SensitiveInformationTypes),City,CountryCode | extend upn = tolower(UserId) | join kind=inner ( AlertEvidence | where Timestamp > ago(31d) | where ProcessCommandLine =='' | extend upnsuffix = todynamic (AdditionalFields).UPNSuffix | extend upn1 = iff(isempty(todynamic (AdditionalFields).Recipient),todynamic (AdditionalFields).Upn,todynamic (AdditionalFields).Recipient) | extend user = parse_json(tostring(todynamic(AdditionalFields).Account)) | extend upn2 = strcat(user.Name,'@',user.UPNSuffix) | extend upn3 = iff(isempty(user.Name),upn1,upn2) | extend upn4 = strcat(AccountName,'@',AccountDomain) | extend upn5 = strcat(AccountName,'@',upnsuffix) | extend upn6 = iff(isempty(upnsuffix),upn4,upn5) | extend upn = iff(isempty(upn3),upn6,upn3) | extend upn = tolower(upn) | extend Type = 'Compromised' | summarize by upn,AttackTitle=Title ) on upn | join kind=leftouter ( IdentityInfo | where Timestamp > ago(7d) | extend AccountUpn = tolower(AccountUpn) | summarize arg_max(Timestamp, *) by AccountUpn ) on $left.UserId == $right.AccountUpn | summarize by tostring(AccessedSite),LabelGUID,UserId,AttackTitle,DataType=tostring(SensitiveInformationTypes),Department,Manager - Name: MicrosoftCopilotActivityperlocation DisplayName: Get the Microsoft Copilot activity labelled and unlabelled as well as data type based on user location and department Description: Fetches the Microsoft Copilot activity labelled and unlabelled as well as data type based on user location and department Inputs: - Name: Department Description: Filter the information for a specific Department Required: false - Name: LabelGUID Description: Filter the information for a specific LabelGUID Required: false Settings: Target: Defender Template: |- let departmentvar = '{{Department}}'; let LabelGUIDvar = '{{LabelGUID}}'; CloudAppEvents | where Timestamp > ago(30d) | where ActionType has 'CopilotInteraction' | extend AccessedResources = iif(array_length(RawEventData.CopilotEventData.AccessedResources)==0, todynamic('Empty:Field') , RawEventData.CopilotEventData.AccessedResources) | mv-expand AccessedResources | extend Content = url_decode(tostring(AccessedResources.SiteUrl)) | extend ObjectName = tolower(replace_string(Content,'?web=1','')) | extend UserId = tostring(RawEventData.UserId) | extend LabelGUID = tostring(AccessedResources.SensitivityLabelId) | where LabelGUID == LabelGUIDvar | extend App = tostring(RawEventData.CopilotEventData.AppHost) | summarize arg_max(Timestamp, *) by UserId,ObjectName,App | join kind=leftouter (CloudAppEvents | where ActionType has 'DLPRuleMatch' | extend sit = parse_json(tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].ConditionsMatched)).SensitiveInformation)) | where sit != '' | mv-expand sit | extend UserId = tolower(RawEventData.UserId) | extend ObjectName = tolower(url_decode(tostring(ObjectName))) | where ObjectName != '' | extend sit_SensitiveInfoTypeName = tostring(sit.SensitiveInformationTypeName) | summarize by sit_SensitiveInfoTypeName,ObjectName | summarize SensitiveInformationTypes = make_list(strcat(sit_SensitiveInfoTypeName)) by ObjectName) on ObjectName | extend AISystemPlugin_ = tostring(parse_json(tostring(parse_json(tostring(RawEventData.CopilotEventData)).AISystemPlugin))) | extend ModelName_ = tostring(parse_json(tostring(parse_json(tostring(RawEventData.CopilotEventData)).ModelTransparencyDetails))[0].ModelName) | extend Id_ = tostring(RawEventData.Id) | summarize AccessedSite = make_list(strcat(ObjectName)) by UserId,Id_,LabelGUID,tostring(SensitiveInformationTypes),City,CountryCode,App | join kind=leftouter ( IdentityInfo | where Timestamp > ago(7d) | extend AccountUpn = tolower(AccountUpn) | summarize arg_max(Timestamp, *) by AccountUpn ) on $left.UserId == $right.AccountUpn | where Department has departmentvar | summarize by AccessedSites=tostring(AccessedSite),RequestId=Id_,App,LabelGUID,tostring(SensitiveInformationTypes),City,CountryCode,Department,JobTitle,Manager,BlastRadius,RiskLevel,RiskLevelDetails - Name: TopUsersByDLPEvidence DisplayName: Get Top Users with Data Loss Prevention Alerts Description: Identifies the top users based on the number of Microsoft Data Loss Prevention alerts and provides a breakdown of alert severity (high, medium, or low) for the last 7 days. Settings: Target: Defender Template: |- let timeframe = 7d; AlertEvidence | where TimeGenerated > ago(timeframe) | where DetectionSource == "Microsoft Data Loss Prevention" | extend AF = todynamic(AdditionalFields) // Don't parse Tags yet, just get basic user info first | extend User = case( isnotempty(AccountUpn), AccountUpn, isnotempty(AF.Name) and AF.Type =~ "account", tostring(AF.Name), "" ) | where isnotempty(User) | summarize TotalAlerts = count() by User | top 5 by TotalAlerts | join kind=inner ( AlertEvidence | where TimeGenerated > ago(timeframe) | where DetectionSource == "Microsoft Data Loss Prevention" | extend AF = todynamic(AdditionalFields) | extend TagInfo = AF.Tags | mv-expand TagInfo | extend User = case( isnotempty(AccountUpn), AccountUpn, isnotempty(AF.Name) and AF.Type =~ "account", tostring(AF.Name), "" ) | extend TagName = tostring(TagInfo.TagName) | extend Severity = case( TagName == "external_user_risk_tag", "High", "Medium" ) | summarize HighSeverity = countif(Severity == "High"), MediumSeverity = countif(Severity == "Medium"), LowSeverity = countif(Severity == "Low") by User ) on User | project User, TotalAlerts, HighSeverity, MediumSeverity, LowSeverity | sort by TotalAlerts desc - Name: DLPAlertsBySeverityAndUser DisplayName: Get DLP Alerts by Severity for a Specific User Description: Retrieves detailed Data Loss Prevention (DLP) alerts for a specific user, filtered by severity. The query provides insights into matched policies, sensitive information types, associated files, confidence levels, enforced actions, and sender/recipient details. Designed to help analysts identify patterns, consolidate alerts, and prioritize incidents for efficient resolution. Inputs: - Name: User Description: The specific user ID to query DLP alerts for (e.g., user@example.com). Required: true - Name: Severity Description: The severity level to filter the alerts (e.g., High, Medium, Low). Required: true Settings: Target: Defender Template: |- let user = '{{User}}'; let severityLevel = '{{Severity}}'; CloudAppEvents | where ActionType has "DLPRuleMatch" and RawEventData.UserId has user and parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].Severity)) == severityLevel | extend PolicyName = tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].PolicyName) | extend SensitiveInformationTypeName = tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].ConditionsMatched)).SensitiveInformation))[0].SensitiveInformationTypeName) | extend FileName = tostring(parse_json(tostring(parse_json(tostring(RawEventData.ExchangeMetaData)).AttachmentDetails))[0].Name) | extend FileSize = toint(parse_json(tostring(parse_json(tostring(RawEventData.ExchangeMetaData)).AttachmentDetails))[0].Size) | extend ConfidenceLevel = toint(parse_json(tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0].ConditionsMatched)).SensitiveInformation))[0].Confidence) | extend Actions = tostring(parse_json(tostring(parse_json(tostring(parse_json(tostring(RawEventData.PolicyDetails))[0].Rules))[0])).Actions) | extend Recipient = tostring(parse_json(tostring(parse_json(tostring(RawEventData.ExchangeMetaData)).To))[0]) | extend Sender = tostring(parse_json(tostring(RawEventData.ExchangeMetaData)).From) | extend IncidentId = tostring(parse_json(tostring(RawEventData)).IncidentId) | extend Timestamp = todatetime(RawEventData.CreationTime) | project Timestamp, PolicyName, SensitiveInformationTypeName, FileName, FileSize, ConfidenceLevel, Actions, Sender, Recipient, Severity = severityLevel, UserId = RawEventData.UserId, IncidentId | order by Timestamp desc - Name: DLPAlertsTopUsersOverview DisplayName: Get Top Users Triggering DLP Alerts Description: This KQL query analyzes DLP rule matches and alerts from CloudAppEvents, identifying users with the highest sensitive info detections and alert counts across SharePoint, OneDrive, Teams, and Endpoints. It distinguishes between alerts with sensitive information types (higher regulatory risk) and alerts without SITs (potential data exfiltration risks), then aggregates alerts by severity, joins them with sensitive info detections, and ranks the top 10 users with the most DLP incidents to highlight potential compliance violations and security threats. Settings: Target: Defender Template: |- let timerange = 30d; // Define the time range for the query // First create a temporary result of sensitive info counts per user let SensitiveInfoCounts = CloudAppEvents | where TimeGenerated > ago(timerange) // Filter events within the specified time range | where ActionType == "DlpRuleMatch" // Filter for DLP rule match events | extend parsedEventData = parse_json(RawEventData) // Parse RawEventData into a structured format | extend Workload = parsedEventData.Workload // Extract the workload //| where Workload != "Exchange" // Uncomment Filter out Exchange events | extend UserPrincipalName = tostring(parsedEventData.UserId) // Extract the user principal name | extend PolicyDetails = parsedEventData.PolicyDetails // Extract policy details | mv-expand PolicyDetails // Expand the PolicyDetails array (one row per policy match) | extend Rules = PolicyDetails.Rules // Extract the Rules field | mv-expand Rules // Expand the Rules array (one row per rule match) | extend ConditionsMatched = parse_json(Rules.ConditionsMatched) // Parse ConditionsMatched to access sensitive info | extend SensitiveInformation = ConditionsMatched.SensitiveInformation // Extract the SensitiveInformation array | mv-expand SensitiveInformation // Expand the SensitiveInformation array (one row per type) | where isnotempty(SensitiveInformation) // Remove rows where SensitiveInformation is empty | summarize SensitiveInfoAlertCount = count() by UserPrincipalName; // Count sensitive info alerts per user // Main query CloudAppEvents | where Timestamp > ago(timerange) // Filter events within the specified time range | extend RawData = parse_json(RawEventData) // Parse RawEventData into a structured format | where RawData.Category == "DataLossPrevention" // Filter for Data Loss Prevention (DLP) events | where RawData.Operation == "AlertTriggered" // Filter for alerts that were triggered | extend DLPAlertId = tostring(RawData.AlertId) // Extract the DLP alert ID | extend Data = parse_json(tostring(RawData.Data)) // Parse the Data field for more details | extend UserPrincipalName = tostring(Data.f3u) // Extract the user principal name | extend MessageType = case( // Categorize the type of message Data.wl == "SharePoint" or Data.wl == "OneDrive", "file", Data.wl == "MicrosoftTeams", "teams", Data.wl == "Endpoint", "endpoint", Data.wl == "Exchange", "exchange", "other" ) //| where MessageType != "Exchange" // Uncomment this to include exchange alerts | extend Severity = tostring(RawData.Severity) // Extract severity level of the alert | summarize AlertCount = count(), // Count total alerts FileAlerts = countif(MessageType == "file"), // Count file-related alerts TeamsAlerts = countif(MessageType == "teams"), ExchangeAlerts = countif(MessageType == "exchange"), // Count Exchange-related alerts EndpointAlerts = countif(MessageType == "endpoint"), // Count endpoint-related alerts ExternalCount = countif(Data.dmc has "IncludeExternalUsers") // Count alerts involving external users by UserPrincipalName, Severity | summarize AlertsByUser = make_bag(pack(Severity, AlertCount)), // Organize alerts by severity FileAlerts = sum(FileAlerts), // Sum of file-related alerts TeamsAlerts = sum(TeamsAlerts), // Sum of Teams-related alerts ExchangeAlerts = sum(ExchangeAlerts), // Sum of Exchange-related alerts EndpointAlerts = sum(EndpointAlerts), // Sum of endpoint-related alerts ExternalCount = sum(ExternalCount), // Sum of alerts involving external users TotalAlerts = sum(AlertCount) // Total alerts per user by UserPrincipalName | extend HighAlerts = tolong(AlertsByUser.High), // Extract high-severity alerts count MediumAlerts = tolong(AlertsByUser.Medium), // Extract medium-severity alerts count LowAlerts = tolong(AlertsByUser.Low), // Extract low-severity alerts count ExternalPercentage = round((ExternalCount * 100.0 / TotalAlerts), 2) // Calculate external alerts percentage // Join with the sensitive info counts | lookup SensitiveInfoCounts on UserPrincipalName | project UserPrincipalName, // User who triggered the alerts TotalAlerts, // Total number of alerts SensitiveInfoAlertCount = coalesce(SensitiveInfoAlertCount, 0), // Count of sensitive info alerts per user HighAlerts = coalesce(HighAlerts, 0), // Count of high-severity alerts MediumAlerts = coalesce(MediumAlerts, 0), // Count of medium-severity alerts LowAlerts = coalesce(LowAlerts, 0), // Count of low-severity alerts FileAlerts, // Count of file-related alerts TeamsAlerts, // Count of Teams-related alerts EndpointAlerts, // Count of endpoint-related alerts ExchangeAlerts, // Count of exchange-related alerts ExternalCount, // Count of alerts involving external users ExternalPercentage // Percentage of external-related alerts | top 10 by TotalAlerts desc // Retrieve the top 10 users with the most alerts - Name: DLPAlertDetailsWithPurviewLink DisplayName: Get Detailed DLP Alert Info with Purview Alert URL Description: This query retrieves detailed information about DLP alerts, including alert ID, policy name, severity, user details, and generates a Purview URL for quick navigation. Inputs: - Name: UPN Description: UPN of the user to search Required: true Settings: Target: Defender Template: |- let timerange = 30d; // Define the time range for the query let searchuser = "{{UPN}}"; // Define the user principal name (UPN) to search for CloudAppEvents | where Timestamp > ago(timerange) // Filter events within the specified time range | extend RawData = parse_json(RawEventData) // Parse RawEventData into a structured format | where RawData.Category == "DataLossPrevention" // Filter for Data Loss Prevention (DLP) events | where RawData.Operation == "AlertTriggered" // Filter for alerts that were triggered | extend DataJson = parse_json(tostring(RawData.Data)) // Parse the Data field for more details | extend User = tostring(DataJson.f3u), // Extract the user who triggered the event Subject = tostring(DataJson.von), // Extract the subject of the event To = tostring(DataJson.["To"]), // Extract recipient information From = tostring(DataJson.mfrm), // Extract sender information Workload = tostring(DataJson.wl) // Extract workload information | where User == searchuser // Filter events specific to the searched user //| where Workload != "Exchange" // Exclude Exchange-related events | project Timestamp, // When the event occurred User, // User who triggered the event Workload, // Workload associated with the event PolicyName = tostring(RawData.Name), // Name of the DLP policy that triggered the event Severity = tostring(RawData.Severity), // Severity level of the alert Subject, // Email or document subject PurviewURL = strcat("https://purview.microsoft.com/datalossprevention/alertspage/fullpage?tid=", tostring(RawEventData.OrganizationId), "&alertsviewid=overview&id=", tostring(RawData.AlertId)) // Construct the Purview alert URL | sort by User desc // Sort results by User in descending order - Name: DLPAlertsSensitiveInfoTypes DisplayName: DLP Alerts with Sensitive Information Types Description: This query retrieves detailed DLP events, highlighting sensitive information types, detection confidence, impacted files or items, and triggered policies across workloads. It provides security analysts with actionable insights to investigate and mitigate potential data leakage incidents effectively. Inputs: - Name: UPN Description: UPN of the user to search Required: true Settings: Target: Defender Template: |- // Define the user principal name (UPN) to search for let searchUser = "{{UPN}}"; CloudAppEvents | where ActionType == "DlpRuleMatch" // Filter for DLP rule matches only | where TimeGenerated > ago(30d) // Look at events from the last 30 days | extend parsedEventData = parse_json(RawEventData) // Parse the RawEventData JSON field into a structured format | where parsedEventData.UserId == searchUser // Filter for events specific to the searched user | extend Workload = parsedEventData.Workload // Extract the workload //| where Workload != "Exchange" // Exclude Exchange-related events | extend PolicyDetails = parsedEventData.PolicyDetails // Extract DLP policy details | mv-expand PolicyDetails // Expand the PolicyDetails array (one row per policy match) | extend Rules = PolicyDetails.Rules // Extract the Rules field | mv-expand Rules // Expand the Rules array (one row per rule match) | extend ConditionsMatched = parse_json(Rules.ConditionsMatched) // Parse ConditionsMatched to access sensitive info | extend SensitiveInformation = ConditionsMatched.SensitiveInformation // Extract the SensitiveInformation array | mv-expand SensitiveInformation // Expand the SensitiveInformation array (one row per type) | where isnotempty(SensitiveInformation) // Remove rows where SensitiveInformation is empty | project TimeGenerated, // When the event occurred UserId = parsedEventData.UserId, // User who triggered the event SensitiveInformationType = SensitiveInformation.SensitiveInformationTypeName, // Type of sensitive info found Confidence = SensitiveInformation.Confidence, // Confidence level of the match Count = SensitiveInformation.Count, // Number of instances found Location = SensitiveInformation.Location, // Where in the content it was found UniqueCount = SensitiveInformation.UniqueCount, // Number of unique instances Workload // Workload associated with the event